当脚本作为Web应用程序部署时,锁定文档上脚本的执行 [英] Lock script execution on a document when script is deployed as web app

查看:66
本文介绍了当脚本作为Web应用程序部署时,锁定文档上脚本的执行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的Google Apps脚本已部署为网络应用,任何用户都可以访问.它的功能是打开和更改该文档中的文本.

My Google Apps Script is deployed as web app and can be accessed by any user. Its functionality is to open and change the text in that document.

我向脚本发送一个 document ID 作为查询参数,如下所示:

I send the script a document ID as a query parameters like so:

https://script.google.com/a/macros/s/AKfycbzCP...TnwHUbXxzDM/exec?docId=1_cMN0nuJadBw6QVjKtdEA6eXhE8ubIoxIJai1ticxnE`

Web应用程序打开文档并更改文档中的文本.

Web app opens the document and changes the text in the document.

function doGet(e){
  var params=e.parameters;
  var doc = DocumentApp.openById(params['docId']);
  ...
  /* change text of the document */
}

问题

现在,当有多个用户试图同时在同一文档上运行应用程序脚本时,Web应用程序将无法处理并发性和功能中断.

Now when there are more than one user trying to run the app-script simultaneously on the same document, the web app fails to handle concurrency and functionality breaks.

我查看了锁定服务,但锁定了服务的文档锁仅适用于容器绑定的脚本,不适用于容器绑定的脚本网络应用.

I looked into Lock Service but lock service's document lock only works for container bound scripts and not for web apps.

然后,我尝试使用缓存服务 var cache = CacheService.getDocumentCache(); 文档:

Then I tried to set property using cache service var cache = CacheService.getDocumentCache(); and property service var documentProperties = PropertiesService.getDocumentProperties(); for the document but document property and document cache returns null in web apps and are restricted to container bound scripts only, as stated in the documentation:

如果在包含的上下文之外调用此方法文档(例如来自独立脚本或Web应用程序)中的此方法返回null.

If this method is called outside of the context of a containing document (such as from a standalone script or web app), this method returns null.

将Google Apps脚本部署为网络应用程序时,是否有任何方法可以处理文档中脚本执行的并发性.(不受容器限制)

Is there any way to handle concurrency for script execution in a document when Google Apps Script is deployed as web app. (Not container bound)

推荐答案

正如@azawaza指出的那样,您应该使用具有适当范围的Lock,并且Script Lock更适合您的方案.在中,此代码是否锁定了onFormSubmit(e)方法正确?

As @azawaza points out, you should be using a Lock with an appropriate scope, and a Script Lock is the better fit for your scenario. This is discussed in Does this code lock the onFormSubmit(e) method correctly?

如果代码的关键部分足够快,则不必担心让用户更新文档2而等待对文档1的另一次更新;他们不会等很久.像这样:

If the critical section of code is sufficiently quick, then there's no real concern about making the user updating Document 2 wait while another update to Document 1 proceeds; they won't wait long. Something like:

function doGet1(e){
  // Perform any "pre" operations on private
  // or non-critical shared resources.
  var params=e.parameters;

  // Get a script lock, because we're about to modify a shared resource.
  var lock = LockService.getScriptLock();
  // Wait for up to 10 seconds for other processes to finish.
  lock.waitLock(10000);

  ////// Critical section begins   vvvvv

  var doc = DocumentApp.openById(params['docId']);

  // change text of the document here

  doc.saveAndClose();

  ////// Critical section ends     ^^^^^
  lock.releaseLock();

  // Continue with operations on private
  // or non-critical shared resources.

  return ContentService.createTextOutput("Document updated.")
}

特定资源锁

开箱即用的Google Apps脚本锁定服务旨在保护关键代码段.如果我们想控制对特定资源(例如很长一段时间)的访问,例如Google文档,则可以通过更改锁定"来适应它.

Specific resource locks

Out of the box, the Google Apps Script Lock Service is designed to protect Critical Sections of code. If we want to control access to a specific resource (perhaps for a long-ish time), such as a Google Document, we can adapt it by changing what we are "locking".

在此示例中,锁定服务保护了关键部分,在该部分中检查并更新了脚本属性.这些属性具有与我们的 docId 参数匹配的键";该值并不重要,因为我们可以使用密钥的简单存在作为我们的测试.

In this example, the Lock service protects a critical section wherein Script Properties are checked and updated. These properties have "keys" that match our docId parameter; the value is not important, as we can use simple existence of the key as our test.

注意:当前,如果另一个脚本无法删除保护用户使用共享文档的属性,则此脚本可能永远"阻止用户(直到脚本超时).您想在生产代码中多加注意.

Note: Currently, this script could block a user "forever" (until script times out) if another script fails to delete the property protecting their use of the shared document. You'd want to take greater care in production code.

function doGet2(e){
  // Perform any "pre" operations on private
  // or non-critical shared resources.
  var params=e.parameters;

  // Wait for exclusive access to docId
  var ready = false;
  // Get a script lock, because we're about to modify a shared resource.
  var lock = LockService.getScriptLock();

  while (!ready) {
    // Wait for up to 1 second for other processes to finish.
    if (lock.tryLock(1000)) {
      ////// Critical section begins   vvvvv      

      var properties = PropertiesService.getScriptProperties();

      // If nobody has "locked" this document, lock it; we're ready.
      if (properties.getProperty(docId) == null) {
        // Set a property with key=docId.
        properties.setProperty(docId,"Locked"); 
        ready = true;
      }

      ////// Critical section ends     ^^^^^
      lock.releaseLock();
    }
  }

  // We have exclusive access to docId now.

  var doc = DocumentApp.openById(params['docId']);

  // change text of the document here

  doc.saveAndClose();

  // Delete the "key" for this document, so others can access it.
  properties.deleteProperty(docId); 

  return ContentService.createTextOutput("Document updated.")
}

命名锁

我们在上一个示例中使用的逻辑可以封装到一个Object中,以提供一个更优雅的界面.实际上,布鲁斯·麦克弗森(Bruce McPherson)的 cNamedLock库,在其桌面解放站点中进行了描述.使用该库,您可以像这样实现特定于文档的锁定:

Named Locks

The logic that we've used in the previous example can be encapsulated into an Object to provide a more elegant interface. In fact, Bruce McPherson has done just that with his cNamedLock Library, described on his Desktop Liberation site. Using that library, you can implement document-specific locking like this:

function doGet3(e){
  // Perform any "pre" operations on private
  // or non-critical shared resources.
  var params=e.parameters;

  // Get a named lock.
  var namedLock = new NamedLock().setKey(docId);

  namedLock.lock();
  ////// Critical section begins   vvvvv      

  // We have exclusive access to docId now.

  var doc = DocumentApp.openById(params['docId']);

  // change text of the document here

  doc.saveAndClose();

  ////// Critical section ends     ^^^^^
  namedLock.unlock();

  return ContentService.createTextOutput("Document updated.")
}

这篇关于当脚本作为Web应用程序部署时,锁定文档上脚本的执行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆