const SLACK_WEBHOOK_URL = '<https://hooks.slack.com/services/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>'; // WebhookのURL
const DEBOUNCE_INTERVAL = 2000; // デバウンス間隔(ミリ秒)
const LOCK_TIMEOUT = 30000; // ロックのタイムアウト(ミリ秒)。最大6分(360000ms)
function onChange(e) {
if (!e || (e.changeType !== 'EDIT' && e.changeType !== 'INSERT_ROW')) {
return; // 不要な呼び出しを防ぐため
}
// --- ロック処理の開始 ---
const lock = LockService.getScriptLock();
try {
// 他のインスタンスが処理中の場合、待機する(最大LOCK_TIMEOUTミリ秒)
// 待機してもロックが取得できない場合は、nullが返る
const hasLock = lock.tryLock(LOCK_TIMEOUT);
if (!hasLock) {
Logger.log('別の処理が進行中のため、スキップします。');
return; // ロックが取得できなかった場合はスキップ
}
// --- デバウンス処理 ---
const properties = PropertiesService.getScriptProperties();
const lastExecutionTimeStr = properties.getProperty('lastExecutionTime');
const lastExecutionTime = lastExecutionTimeStr ? parseInt(lastExecutionTimeStr, 10) : 0;
Logger.log('PropertiesServiceから取得したlastExecutionTime: ' + lastExecutionTime);
const currentTime = new Date().getTime();
Logger.log('現在の時間: ' + currentTime);
Logger.log('経過時間: ' + (currentTime - lastExecutionTime));
if (currentTime - lastExecutionTime < DEBOUNCE_INTERVAL) {
Logger.log('デバウンスにより処理がスキップされました。');
return; // デバウンス間隔内の場合はスキップ
}
const sheet = e.source.getActiveSheet();
const lastRow = sheet.getLastRow();
const flagColumn = 17; // Q列は17列目
// --- 「処理済み」フラグの最終チェックと設定 ---
const flag = sheet.getRange(lastRow, flagColumn).getValue();
if (flag === '処理済み') {
Logger.log('この行はすでに処理済みです。(二重チェック)');
return; // 処理済みの場合は終了
}
// ここでフラグを設定し、次のイベントトリガーがすぐに起動しないようにする(重要)
// この setValue が新たな onChange を発火させる可能性があるため、注意
sheet.getRange(lastRow, flagColumn).setValue('処理済み');
SpreadsheetApp.flush(); // スプレッドシートへの変更を即座に反映させる
const data = sheet.getRange(lastRow, 1, 1, sheet.getLastColumn()).getValues()[0];
const message = createSlackMessage(data);
try {
sendToSlack(message);
Logger.log('Slackへの送信成功。lastExecutionTimeを更新します。');
// Slack送信成功後のみ最終実行時間を更新
properties.setProperty('lastExecutionTime', currentTime.toString());
} catch (error) {
Logger.log('Slackへの送信エラー: ' + error);
// エラーが発生した場合はフラグを元に戻すなど、エラーハンドリングを検討
sheet.getRange(lastRow, flagColumn).setValue(''); // 例: フラグをクリア
}
} finally {
// --- ロックの解放 ---
if (lock) { // ロックが取得できた場合のみ解放
lock.releaseLock();
Logger.log('ロックを解放しました。');
}
}
}
// ... createSlackMessage, sendToSlack は変更なし
function createSlackMessage(data) {
const schedule = data[1]; // スケジュール
const cancelReason = data[4]; // キャンセル理由
const participants = data[6]; // 参加メンバー
const companyName = data[8]; // 会社名
const name = data[9]; // 名前
const comment = data[10]; // コメント
const lineInstagramName = data[13]; // LINE/Instagramのお名前
return {
text: `スケジュール: ${schedule}\n` +
`キャンセル理由: ${cancelReason}\n` +
`参加メンバー: ${participants}\n` +
`会社名: ${companyName}\n` +
`名前: ${name}\n` +
`コメント: ${comment}\n` +
`LINE/Instagramのお名前: ${lineInstagramName}`,
};
}
function sendToSlack(message) {
const options = {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(message),
};
const response = UrlFetchApp.fetch(SLACK_WEBHOOK_URL, options);
Logger.log('Response: ' + response.getContentText());
}