GASLockで競合回避
GAS応用とLockServiceの基本
Google Apps Script(GAS)は、スプレッドシートやドキュメントを自動化するだけでなく、外部APIとの連携や定期実行タスクの構築にも活用できます。GASを実務で応用する際に直面する課題の一つが、複数のユーザーやトリガーが同時にスクリプトを実行したときに発生する競合です。ここで重要になるのが、LockServiceを使った排他制御です。
LockServiceは、スクリプト全体または特定のリソースに対してロックを取得し、同時実行を防止するためのAPIです。主に3種類のロックが用意されており、今回は getScriptLock() と tryLock() を中心に解説します。
function example() {
var lock = LockService.getScriptLock();
try {
lock.waitLock(30000); // 30秒待機
// ここにクリティカルセクション
} catch (e) {
Logger.log('ロック取得失敗: ' + e);
} finally {
lock.releaseLock();
}
}
上記のように waitLock() を使うと、ロックが取得できるまで待機しますが、待機時間が長いとユーザー体験が低下します。そこで tryLock() を使うと、ロック取得に失敗した場合に即座に処理をスキップでき、非同期処理の設計に適しています。
排他制御で同時実行対策を実装する
同時実行対策は、データベース更新やファイル書き込みなど、状態を変更する処理で特に重要です。GASでは tryLock() を組み合わせて、以下のように実装します。
function updateSheet() {
var lock = LockService.getScriptLock();
if (!lock.tryLock(1000)) { // 1秒でロック取得を試みる
Logger.log('別のプロセスが実行中です。');
return;
}
try {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Data');
var lastRow = sheet.getLastRow() + 1;
sheet.getRange(lastRow, 1).setValue(new Date());
// 追加の更新処理
} finally {
lock.releaseLock();
}
}
このパターンでは、ロック取得に失敗した場合に即座に処理を終了し、競合回避と安全性を確保します。さらに、ロック取得に失敗した際に再試行ロジックを組み込むことで、より堅牢な設計が可能です。
排他制御を実装する際のポイントは次の通りです。
- ロック対象は最小限に抑える(例:特定のシートやファイルのみ)
- ロック保持時間は短くする(処理を分割してロックを解放)
- ロック取得失敗時のフォールバック処理を用意する
データ整合性と重複防止のベストプラクティス
排他制御を行うことで同時実行による競合を防げますが、データ整合性を保つためにはさらに工夫が必要です。特に、重複防止のロジックを組み込むことで、同じデータが複数回書き込まれるリスクを低減できます。
例えば、スプレッドシートにログを追加する際に、既に同じタイムスタンプと内容が存在するかを確認し、重複があればスキップする処理を入れます。
function logEntry(entry) {
var lock = LockService.getScriptLock();
if (!lock.tryLock(1000)) {
Logger.log('ロック取得失敗。重複チェックをスキップ。');
return;
}
try {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Log');
var data = sheet.getDataRange().getValues();
var exists = data.some(function(row) {
return row[0] === entry.timestamp && row[1] === entry.message;
});
if (!exists) {
sheet.appendRow([entry.timestamp, entry.message]);
} else {
Logger.log('重複エントリをスキップ。');
}
} finally {
lock.releaseLock();
}
}
このように、ロックと重複チェックを組み合わせることで、データ整合性と安全性を高めることができます。また、トランザクションのように複数の操作をまとめて実行する場合は、ロックを取得した状態で全ての操作を完了させ、途中で失敗した場合はロールバック(例:書き込んだ行を削除)を行う設計が推奨されます。
まとめとして、GAS応用においては LockService を活用した排他制御が不可欠です。getScriptLock() と tryLock() を適切に使い、同時実行対策、データ整合性、重複防止、競合回避、安全性を確保することで、安定したスクリプト運用が実現できます。
コメント
コメントを投稿