G Suiteの大きな特徴の1つとして、複数名同時に同一ドキュメントに対して作業が出来るコラボレーション機能です。ですが、例えばスプレッドシート上で大きなコピペをするスクリプトを複数名が同時に使った場合、ややこしい事になってしまいます(更に言えば連番を取って付け加える場合、番号がめちゃくちゃになります)。

そこで使用するのが排他制御。排他制御とは別の誰かが実行している場合には、そのスクリプトの実行をロックさせてしまう機能で、一方が実行中はもう一方はその実行を待たせる機能です。指定した秒数以上待たされた場合には、エラーが発生するので、通常try〜catch文も合わせて使用するのが定石です。

排他制御には3種類のタイプがあります。

今回使用するスプレッドシート

  • 排他制御サンプル1 – 3種類の排他制御コードが入っています(ライブラリ元でもある)
  • 排他制御サンプル2 – スクリプトロックをサンプル1からライブラリとして呼び出すコードだけが入ってる

※サンプルではcopypaste()というメインルーチンをそれぞれのルーチンから呼び出しています。

概要

LockServiceというクラスを使用するのですが、3種類のロックサービスがあります。必ず冒頭でロックを宣言して、その後指定秒数のロックを実施、最期に必ずロックをリリースするといった一連の手順が必要になっています(でなければタイムアウトするまでロックされっぱなしになります)。

指定秒数よりも前にスクリプトが終了した場合、待たされていた側は即時にスクリプトが実施されるようになります。逆に指定秒数以上待たされた場合にはエラーが発生しスクリプトの実行がキャンセルされます。

ロックは、DocumentLock、UserLock、ScriptLockがありそれぞれに特徴があります。また指定秒数のロックの実施ではtryLockとwaitLockの2つがあり、これもまた少し挙動が異なります。最期にreleaseLockでロックを開放するわけです。

図:地味な機能だけれど習得必須の機能です

tryLockとwaitLockの違い

指定秒数のロックを取得する際に使う2つのメソッドですが、両者はちょっと挙動が異なります。tryLockはロックを取得時に誰かがロックをしてて指定秒数超えるとfalseが返ってくる仕組みです。一方、waitLockはfalseが返ってくるのではなくエラーが発生する仕組みになっているので、try〜catchが必要です。

tryLockの使い方

※Lock取得に失敗したらfalseが返ってくるので、if文でロック取得を試みて失敗時にはelse文以下に処理が移り、メッセージをユーザに伝える処理を記述します。ロックが取得できても、メインルーチンでエラーが発生した時に備えて、try〜catch〜finally文でエラートラップの処理をきちんとしておいてあげます。

waitLockの使い方

tryLockよりも少々処理の記述法がより高度になっています。自分は通常こちらを使っています。try〜catch〜finally文も一部ではなく全体にたいして掛けて、最期にreleaseLockで開放し成功時・エラー時のメッセージをユーザに表示するようにしています。タイムアウトなのか?メインルーチンのエラーなのか?を区別するために、checkwordにてタイムアウトかどうかを判定させています。

ソレ以外の場合はe.messageにてエラー内容をメッセージに加えています。

hasLockの使い方

tryLockとwaitLockの他にもhasLockと呼ばれる検証用のメソッドがあります。このメソッドは「ロックがされているかどうか?」を調べる為のメソッドで、tryLockなどの後で、hasLockでテストをし、例えばロックが取れているかどうか?を元に処理をさせることが出来ます。hasLockでfalseが返ってきた場合には、速攻でその場でスクリプトの実施をキャンセルさせる事が可能です。

ロックを使ってみる

ドキュメントロック

ドキュメントロックとは、同一ドキュメントに対するスクリプトの実施をロックする為のメソッドです。同一ドキュメントに対する処理がロックされるので、通常これを使う事が多いです。同一人物であろうとなかろうと区別しません。特にユニークIDの生成やそれに対するスプレッドシートへの書き込み処理では必須のロックです。

実施テストは、サンプル1のスプレッドシートにてメニューより「作業実行」⇒「ドキュメントロック」でテストが出来ます。2つ以上のアカウントで同じスクリプトを同時に実施してみると挙動がわかると思います。20秒間のロックを加えています。

ユーザーロック

ユーザロックとは、同一ユーザによるスクリプトの実施をロックするためのメソッドです。よって、別の人が同時にスクリプトを実施出来てしまいますので注意が必要です。主に同一人物による二重起動をロックするために使います。あまりスプレッドシートへの書き込みなど他人とバッティングはしない処理に対して使用します。

実施テストは、サンプル1のスプレッドシートにてメニューより「作業実行」⇒「ユーザロック」でテストが出来ます。複数人物で同じスクリプトを実施すると挙動がわかります。同時に実行出来てしまう点で区別が付きます。

スクリプトロック

スクリプトロックはちょっと特殊です。同一スクリプトの実施に対してロックを掛けるので、表面上はドキュメントロックと挙動がほぼ同じです。ですが、このロックの使い方はそうではありません。これは通常ライブラリ化したルーチンの中で使用し、同一スクリプトだけれど、別のドキュメントでそれぞれ参照し利用している場合に使います。

今回はサンプル1にスクリプトロックのメインルーチンを記述しライブラリ化、サンプル2にそのライブラリを呼び出して流用させています。サンプル1のシートで実行後サンプル2で実施しても、最初に呼び出した側の処理が終わるまで、サンプル2側の処理はスクリプトは待機させられます。主に、2つのシートでユニークなIDを降る時に両シートで重複しないように降るといったような処理で利用出来ます。

実施テストはサンプル1のスプレッドシートメニューより「作業実行」⇒「スクリプトロック」を実施。サンプル2で「作業実行」⇒「スクリプトロック」を同時に実施すると挙動がわかります。サンプル2はサンプル1の実施が終わるまで待機しています。

サンプル2側はメインルーチンまるごと存在せず呼び出しているだけです(lockmanとう名前でサンプル1のライブラリを追加してあります)。

一応コピペのルーチン

今回は排他制御の為のエントリーですので、コピペするルーチンはおまけです。ここで注目すべきは同時実施やスクリプトロック実行時のIDの値の付き方です。このルーチンは全てのスクリプトロックサンプルスクリプトで呼び出していて、ユニークIDも共用させています。故に、IDの付き方に差が付きます。

関連リンク