見出し画像

GASの排他制御について


今回はGASの排他制御について説明して行きます。
そもそも排他制御とは、「同一資源の共同利用による整合性の破綻」を防ぐための仕組みです。
つまりこれが必要になるのは同じ資源を複数人で使う場面です。
GASではこのようなシーンが想定されます。

  • Aさんが「関数2」を介してシートを利用

  • BさんとCさんが「関数3」を介してシートを利用

  • Dさんは直接シートを利用

このとき、関数2,3に以下のような最後尾に1行追加する処理が設定されている場合、同時に実行されると、正常に反映されず最終行が上書きされる可能性があります。また、Dさんが直接最終行に1行追加する場合も同様です。

//関数2

function addDate(){
 const ss = SpreadsheetApp.getActive()
 const sh = ss.getSheetByName("シート1")
 const date = Utlities.formatDate(new Date(),"Asia/Tokyo","yyyy/MM/dd")
 sh.appendRow([date])
 
} 

//関数3

function addTime(){
 const ss = SpreadsheetApp.getActive()
 const sh = ss.getSheetByName("シート1")
 const time = Utlities.formatDate(new Date(),"Asia/Tokyo","HH:mm")
 sh.appendRow([time])
 
}

このように「スプレッドシート」あるいは「関数」といった資源を共同利用すると、場合によっては「最終行」などの整合性が破綻する恐れがあります。

これを防ぐためにGASのLockServiceクラスを利用します。

LockServiceクラス

これを呼び出すと対象に"錠前"が出現し利用を制限できます。従来はどこからでも利用できた関数やシートの入り口がこの扉に限定され、尚且つ一単位ずつしか入れなくなります。

この"錠前"を出現させる対象は3種類あるため、メソッドも3種類存在します。いずれも戻り値はLockオブジェクト(≒錠前)です。

.getDocumentLock()

このメソッドはコンテナされているスプレッドシートやdocsなどのGoogleサービス自体に錠前をつけます。従って、スタンドアロンスクリプトからは呼び出せません。

.getScriptLock()

このメソッドは関数に錠前を設定できます。従ってある関数をAさんが実行してる間はBさんは実行できなくなります。

.getUserLock()

このメソッドはユーザーに錠前を設定できます。従って関数1をAさんが実行中、Aさんは二重で実行できません。(他の人は同時に関数1を実行できます。)


ただ、これら3つのメソッドはあくまで錠前を設定するだけです。
鍵かけただけでは誰も使えないので、利用するには開錠が必要です。

開錠のメソッドを3種類紹介します。

Lockオブジェクト

↑3つの戻り値である錠前オブジェクトです。

.tryLock()

引数に指定したミリ秒間解除を試み、成功すると開錠できます。
指定の時間内に他社の利用が終わらないなど開錠できない場合はfalseを返します。先の関数2に当てはめるとこのようになります。

//関数2

function addDate(){
 const ss = SpreadsheetApp.getActive()
 const sh = ss.getSheetByName("シート1")
 const lock = LockServile.getDocumentLock()
 lock.tryLock(1000*10){
  const date = Utlities.formatDate(new Date(),"Asia/Tokyo","yyyy/MM/dd")
  sh.appendRow([date])
 }
}

10秒間で開錠を試み、他社のシートの利用が終われば今日の日付を最終行に追加できます。開錠できない(他社の利用が終わらない)場合、falseとなり最終行には何も追加されません。
従ってif文で条件分岐できます。

.tryWait()

こちらも同様引数に指定したミリ秒間解錠を試み成功した場合のみ処理が実行されますが、解錠できなかった場合にerrorオブジェクトを発生させます。
従ってtrycatchで条件分岐できます。

.releaseLock()

一度開錠して資源を利用した後、鍵を元に戻すメソッドです。
これを呼び出すと他の誰かが開錠できるようなります。

.hasLock()

自身が開錠してるかを判定するメソッドです。他者が処理中、あるいはtryLockやwaitLockなどロックを獲得するメソッドを一度も実行してない、またはreleaseLockで錠前を手放している場合などはfalse、自分が開錠して資源利用を中ならtrueを返します。

まとめ

適切な範囲に対して錠前を設定し、1単位ずつの利用に制限する事でシステムの整合性を担保します。

いずれにしても、スクリプトを介した制御しかできないので、シート自体を直接触れないように権限を設定しておくことをお勧めします。

この記事が気に入ったらサポートをしてみませんか?