GASで処理の同時実行を避けるLockserviseによる排他処理の実装方法

実装方法概要

以下の実装例はタイムアウト時にエラーとする例。エラーとしない場合については後述。


function myFunction(){
  // ロック取得。この時点ではロック自体はかからない。
  var lock = LockService.getScriptLock()
  try{

    // タイムアウトミリ秒(1000=1秒)
    var timeoutInMillis = 60000
    // ロック取得の実行。失敗した場合にエラーとする。成功した場合は処理継続。
    lock.waitLock(timeoutInMillis)

    // ここに処理を実装。

  }catch(e){
    console.error(e.name)    // Exception
    console.error(e.message) // Lock timeout: another process was holding the lock for too long.
  }finally{
    // ロックの解除の実施。hasLockで現在ロック実施中かが取得できる。
    if(lock&&lock.hasLock()){
      lock.releaseLock()
    }
  }
}

ロック取得

LockServiceのgetから始まる3つのメソッドのいずれかを使用して取得します。

  • getScriptLock
    • 処理が実行されているスクリプト(GASプロジェクト)単位でのロックを取得します。
  • getDocumentLock
    • 処理が実行されているドキュメント(スプレッドシートetc…)単位のロックを取得します。
  • getUserLock
    • 処理を実行しているユーザー単位のロックを取得します。

基本的にはgetScriptLockを使用すれば問題ないと思います。

動作について詳しく知りたい方は別ページで解説しているので以下の記事を合わせて読んでください。

ロックの実施

タイムアウト時にエラーとする方法

タイムアウト時にエラーとしたい場合は、waitLockを利用します。

第一引数にタイムアウトとするミリ秒数を設定して呼び出しを行います。

ロックがすでにかかっている場合はタイムアウトまでロックの実施のリトライを行われ、タイムアウトするとエラーとなります。


  // ロック取得。この時点ではロック自体はかからない。
  var lock = LockService.getScriptLock()
  var timeoutInMillis = 60000
  // ロック取得の実行。失敗した場合にエラーとする。成功した場合は処理継続。
  lock.waitLock(timeoutInMillis)

タイムアウト時にエラーとしない方法

タイムアウト時にエラーとしない場合は、tryLockを利用します。

waitLockと同じように第一引数にタイムアウトとするミリ秒数を設定して呼び出しを行います。

ロックが成功した場合はtrue、失敗するとfalseが返却されます。

返却値を変数に設定し処理の分岐を行うことができます。

  // ロック取得。この時点ではロック自体はかからない。
  var lock = LockService.getScriptLock()
  // ロックの実行。
  var hasLock = lock.tryLock(10000)
  
  if(hasLock){
    console.info("ロック成功")
  }else{
    console.info("ロック失敗")
  }

現在のセッションにおいてのロック状態の取得

現在のセッションにおいてのロック状態の取得を行うにはhasLockを使用します。

他セッションでのロック状態の取得は行えないのでご注意。


  // ロック取得。この時点ではロック自体はかからない。
  var lock = LockService.getScriptLock()
  // ロックの実行。
  lock.tryLock(10000)
  
  if(lock.hasLock()){
    console.info("ロック成功")
  }else{
    console.info("ロック失敗")
  }

公式リファレンス

https://developers.google.com/apps-script/reference/lock?hl=ja

以上です。読んでくれた方ありがとうございました。

コメントフォーム