GoogleスプレッドシートのApps Scriptで複数のユーザーが同時にスクリプトを実行すると、データの競合が発生することがあります。特にセルの値を読み書きする処理では、予期しない結果になることがあるため、注意が必要です。LockServiceを使うことで、スクリプトの実行を一時的にロックし、競合を回避できます。この記事では、LockServiceの基本的な使い方から応用までを具体的なコード例とともに解説します。
【要点】LockServiceで並行実行の競合を防ぐ方法
- getScriptLock(): スクリプト全体をロックします。複数の関数やユーザー間で排他制御を行いたい場合に使用します。
- getUserLock(): 同一ユーザー内での同時実行を防ぎます。同じユーザーが複数のタブでスクリプトを実行する場合に有効です。
- tryLock(timeoutInMillis) または waitLock(timeoutInMillis): ロックの待機方法を選択します。tryLockは即座に結果を返し、waitLockはロックが解放されるまで待機します。
ADVERTISEMENT
目次
LockServiceを使った排他制御の仕組み
Apps ScriptはGoogleのサーバー上で動作するため、複数のユーザーが同時に関数を実行することがあります。その際、スプレッドシートの同じセルに対して書き込みを行うと、データが上書きされたり中途半端な状態になる可能性があります。LockServiceはスクリプトのクリティカルセクションにロックをかけることで、同時実行をシリアル化します。ロックはスクリプトプロジェクト、ユーザー、またはドキュメント単位で設定でき、適切なスコープを選ぶことが重要です。
並行実行で起こる問題
たとえば、在庫管理のスクリプトで複数のユーザーが同時に発注処理を行うと、在庫数が正確に更新されず、二重発注や在庫切れなどの問題が発生します。LockServiceを使用しない場合、このような競合を防ぐことはできません。
LockServiceの3つのロック
LockServiceには3種類のロックがあります。getScriptLock()はスクリプト全体にロックをかけ、すべてのユーザーとすべての関数で排他制御を行います。getUserLock()は同一ユーザーに限定したロックで、同じユーザーが複数のタブでスクリプトを実行する場合に使います。getDocumentLock()はドキュメント単位のロックで、他のドキュメントの関数とは競合しません。用途に応じて適切なロックを選びましょう。
LockServiceを使った排他制御の実装手順
基本のロック取得と解放
まず、ロックを取得し、処理が終わったら必ず解放する基本パターンを理解しましょう。以下のコードは、スプレッドシートのセルに値を書き込む関数に排他制御を追加した例です。
function writeDataWithLock(value) {
var lock = LockService.getScriptLock();
lock.tryLock(10000); // 10秒間ロックを試みる
if (!lock.hasLock()) {
Logger.log('ロックの取得に失敗しました');
return;
}
try {
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange('A1').setValue(value);
} finally {
lock.releaseLock();
}
}
tryLock()は指定したミリ秒だけロックを試み、取得できたかどうかをブール値で返します。ロックが取得できた場合のみ処理を行い、finallyブロックで必ず解放します。これで同時実行による競合を防げます。
タイムアウト付きロックとエラーハンドリング
ロックが取得できない場合の処理をより堅牢にするには、waitLock()を使用する方法もあります。waitLock()はロックが取得できるまでブロックしますが、タイムアウトを設定すると例外がスローされます。その例外をキャッチして適切に処理しましょう。
function writeDataWithWaitLock(value) {
var lock = LockService.getScriptLock();
try {
lock.waitLock(15000); // 15秒待機、取得できないと例外
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange('A1').setValue(value);
} catch (e) {
Logger.log('ロック待機中にエラーが発生しました: ' + e.toString());
} finally {
lock.releaseLock();
}
}
waitLock()はロックが解放されるまで待ち続けますが、タイムアウトに達するとエラーが発生します。エラーハンドリングを実装することで、ユーザーにわかりやすいメッセージを表示できます。
実際の活用例:在庫更新処理
以下は、複数のユーザーが在庫数を更新する場合の実装例です。この例では、在庫数を読み取り、1減らして書き戻す処理を排他制御で保護しています。
function updateStock(itemId, quantity) {
var lock = LockService.getScriptLock();
if (!lock.tryLock(5000)) {
throw new Error('ロックの取得に失敗しました。時間をおいて再試行してください。');
}
try {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('在庫');
var data = sheet.getDataRange().getValues();
for (var i = 0; i < data.length; i++) {
if (data[i][0] === itemId) {
var currentStock = data[i][1];
if (currentStock < quantity) {
throw new Error('在庫が不足しています。');
}
sheet.getRange(i + 1, 2).setValue(currentStock - quantity);
break;
}
}
} finally {
lock.releaseLock();
}
}
このように、ロックを使って一連の操作をアトミックにすることで、データの整合性を保つことができます。
LockService使用時の注意点
ロックの解放忘れ
ロックを取得したら、必ずfinallyブロックで解放してください。解放を忘れると、他のスクリプトが永久にロックを取得できなくなり、システムが停止します。また、スクリプトがエラーで中断された場合も確実に解放されるように、try...finallyの構文を使用しましょう。
タイムアウト時間の設定
タイムアウト時間はロックの待機時間の上限です。短すぎると頻繁にロック取得に失敗し、長すぎるとユーザー体験を損ないます。スクリプトの実行時間制限(通常6分)も考慮し、適切な値を設定してください。目安として、5~15秒程度が一般的です。
スコープの選択ミス
getScriptLock()とgetUserLock()の違いを理解せずに使用すると、意図しない挙動になります。例えば、同一ユーザーのみの排他で十分な場合にスクリプト全体をロックしてしまうと、他のユーザーの処理までブロックして効率が低下します。用途に応じて適切なロックを選びましょう。
ADVERTISEMENT
3種類のロックの比較
| ロックの種類 | スコープ | 用途 | 注意点 |
|---|---|---|---|
| getScriptLock() | スクリプト全体 | 複数の関数や異なるユーザー間で排他制御が必要な場合 | 他のユーザーもブロックされるため、長時間のロックは避ける |
| getUserLock() | 同一ユーザー | 同一ユーザーが複数のタブで同時実行するのを防ぎたい場合 | 異なるユーザー間では競合しない |
| getDocumentLock() | 特定のドキュメント | 特定のスプレッドシートやドキュメントに対し排他制御を行いたい場合 | 他のドキュメントのスクリプトとは競合しない |
まとめ
この記事では、GoogleスプレッドシートのApps ScriptでLockServiceを使用した排他制御の方法を解説しました。LockServiceを使うことで、並行実行によるデータ競合を防止し、処理の整合性を保つことができます。適切なロックの種類とタイムアウトを設定し、必ずfinallyで解放することを忘れないでください。この仕組みを活用して、安全なスクリプトを作成しましょう。
ADVERTISEMENT
超解決 第一編集部
疑問解決ポータル「超解決」の編集チーム。正確な検証と、現場視点での伝わりやすい解説を心がけています。
Googleスプレッドシートの人気記事ランキング
- 【Googleスプレッドシート】GOOGLEFINANCE関数で株価・為替を取得!リアルタイムデータの呼び出し
- 【Googleスプレッドシート】印刷範囲を指定して印刷!特定範囲だけPDFや紙に出す手順
- 【Googleスプレッドシート】新しいスプレッドシートを作成する3つの方法!ドライブ・URL・テンプレート
- 【Googleスプレッドシート】数値の連続データを自動入力!オートフィルの活用
- 【Googleスプレッドシート】ダークモードを有効にする!目に優しい配色への切替
- 【Googleスプレッドシート】株価APIで株式データを自動取得!GOOGLEFINANCE超え活用
- 【Googleスプレッドシート】共有相手が編集できない時のチェック!権限と許可状態の確認
- 【Googleスプレッドシート】ページ設定で用紙サイズと向きを調整!印刷レイアウトの基本
- 【Googleスプレッドシート】Excelファイルxlsxをインポートする手順!ドラッグ&ドロップで取り込み
- 【Googleスプレッドシート】条件付き書式をコピーする!書式のみペーストの活用
