【问题标题】:Google calendar API. Modifications loss when simultaneously patching event谷歌日历 API。同时修补事件时修改丢失
【发布时间】:2021-06-29 10:04:39
【问题描述】:

我有处理 webhook 的 firebase 函数。

此功能更新日历事件,单个事件可以同时更新。

我使用 Etag 和 If-Match 标头来防止修改丢失,如 doc 中所述。

但我仍然丢失了除最后一个之外的所有更改。

此代码对同一事件进行多次同时更新。

结果摘要中必须是“10”,但实际上是“2”。

这有什么问题?

代码

const calendarId = 'calendarid';
const scopes = [
  "https://www.googleapis.com/auth/calendar",
  "https://www.googleapis.com/auth/calendar.events",
];
const auth = new google.auth.GoogleAuth({ scopes });
const calendar = google.calendar({ version: "v3", auth });

...

const reproduce = async () => {
  const {id: eventId} = await calendar.events.insert({
    auth,
    calendarId,
    resource: {
      summary: '1',
      // some another resource data
    },
  });

  const update = async () => {
    const event = await calendar.events.get({
      auth,
      calendarId,
      eventId,
    });

    console.log("***BEFORE***");
    console.log("summary: " + event.summary);
    console.log("etag: " + event.etag);
    
    const previousSummary = event.summary;
    const newSummary = parseInt(previousSummary) + 1;

    const res = await calendar.events.patch({
      auth,
      calendarId,
      eventId,
      resource: {summary: newSummary.toString()},
    }, {
      headers: {
        "If-Match": event.data.etag
      }
    });
    
    console.log("***AFTER***");
    console.log("summary: " + res.data.summary);
    console.log("etag: " + res.data.etag);
  }

  let i = 0;
  // simultaneously updates event
  while (i++ < 10) {
    update();
  }
}

输出

>  ***BEFORE***
>  summary: 1
>  etag: "3235006977030000"
>  ***BEFORE***
>  summary: 1
>  etag: "3235006977030000"
>  ***BEFORE***
>  summary: 1
>  etag: "3235006977030000"
>  ***BEFORE***
>  summary: 1
>  etag: "3235006977030000"
>  ***BEFORE***
>  summary: 1
>  etag: "3235006977030000"
>  ***BEFORE***
>  summary: 1
>  etag: "3235006977030000"
>  ***BEFORE***
>  summary: 1
>  etag: "3235006977030000"
>  ***BEFORE***
>  summary: 1
>  etag: "3235006977030000"
>  ***BEFORE***
>  summary: 1
>  etag: "3235006977030000"
>  ***AFTER***
>  summary: 2
>  etag: "3235006998028000"
>  Event updated successfully
>  ***AFTER***
>  summary: 2
>  etag: "3235007000852000"
>  Event updated successfully
>  ***AFTER***
>  summary: 2
>  etag: "3235007002822000"
>  Event updated successfully
>  ***AFTER***
>  summary: 2
>  etag: "3235007003202000"
>  Event updated successfully
>  ***AFTER***
>  summary: 2
>  etag: "3235007004826000"
>  Event updated successfully
>  ***AFTER***
>  summary: 2
>  etag: "3235007009742000"
>  Event updated successfully
>  ***AFTER***
>  summary: 2
>  etag: "3235007011058000"
>  Event updated successfully
>  ***AFTER***
>  summary: 2
>  etag: "3235007014902000"
>  Event updated successfully
>  ***AFTER***
>  summary: 2
>  etag: "3235007018050000"
>  Event updated successfully

【问题讨论】:

    标签: google-calendar-api etag


    【解决方案1】:

    我能够在 Apps 脚本中使用 Javascript 重现您的问题。 您能够更新您的事件一次(使您的摘要为“2”)的原因是因为您在 update() 中的 async/await 命令。

    示例代码:

     const update =  async () => {
        const event =  await Calendar.Events.get(
          calendarId,
          eventId,
        );
    
        Logger.log("***BEFORE***");
        Logger.log("summary: "+event.summary);
        Logger.log("etag: "+event.etag);
        const previousSummary = event.summary;
        const newSummary = parseInt(previousSummary) + 1;
    
    
        const res =  await Calendar.Events.patch(
          {summary: newSummary.toString()},
          calendarId,
          event.id,
          { "If-Match": event.etag }
         );
        
        Logger.log("***AFTER***");
        Logger.log("summary: "+res.summary);
        Logger.log("etag: "+res.etag);
        //Logger.log(res);
      }
    
    let i = 0;
    // simultaneously updates event
    while (i++ < 10) {
      update();
    }
    

    输出:

    12:04:47 AM Notice  Execution started
    12:04:51 AM Info    ***BEFORE***
    12:04:51 AM Info    summary: 1
    12:04:51 AM Info    etag: "3234758978180000"
    12:04:51 AM Info    ***BEFORE***
    12:04:51 AM Info    summary: 1
    12:04:51 AM Info    etag: "3234758978180000"
    12:04:52 AM Info    ***BEFORE***
    12:04:52 AM Info    summary: 1
    12:04:52 AM Info    etag: "3234758978180000"
    12:04:52 AM Info    ***BEFORE***
    12:04:52 AM Info    summary: 1
    12:04:52 AM Info    etag: "3234758978180000"
    12:04:52 AM Info    ***BEFORE***
    12:04:52 AM Info    summary: 1
    12:04:52 AM Info    etag: "3234758978180000"
    12:04:53 AM Info    ***BEFORE***
    12:04:53 AM Info    summary: 1
    12:04:53 AM Info    etag: "3234758978180000"
    12:04:53 AM Info    ***BEFORE***
    12:04:53 AM Info    summary: 1
    12:04:53 AM Info    etag: "3234758978180000"
    12:04:53 AM Info    ***BEFORE***
    12:04:53 AM Info    summary: 1
    12:04:53 AM Info    etag: "3234758978180000"
    12:04:54 AM Info    ***BEFORE***
    12:04:54 AM Info    summary: 1
    12:04:54 AM Info    etag: "3234758978180000"
    12:04:54 AM Info    ***BEFORE***
    12:04:54 AM Info    summary: 1
    12:04:54 AM Info    etag: "3234758978180000"
    12:04:54 AM Info    ***AFTER***
    12:04:54 AM Info    summary: 2
    12:04:54 AM Info    etag: "3234758983260000"
    12:04:54 AM Info    ***AFTER***
    12:04:54 AM Info    summary: 2
    12:04:54 AM Info    etag: "3234758983260000"
    12:04:54 AM Info    ***AFTER***
    12:04:54 AM Info    summary: 2
    12:04:54 AM Info    etag: "3234758983260000"
    12:04:54 AM Info    ***AFTER***
    12:04:54 AM Info    summary: 2
    12:04:54 AM Info    etag: "3234758983260000"
    12:04:54 AM Info    ***AFTER***
    12:04:54 AM Info    summary: 2
    12:04:54 AM Info    etag: "3234758983260000"
    12:04:54 AM Info    ***AFTER***
    12:04:54 AM Info    summary: 2
    12:04:54 AM Info    etag: "3234758983260000"
    12:04:54 AM Info    ***AFTER***
    12:04:54 AM Info    summary: 2
    12:04:54 AM Info    etag: "3234758983260000"
    12:04:54 AM Info    ***AFTER***
    12:04:54 AM Info    summary: 2
    12:04:54 AM Info    etag: "3234758983260000"
    12:04:54 AM Info    ***AFTER***
    12:04:54 AM Info    summary: 2
    12:04:54 AM Info    etag: "3234758983260000"
    12:04:54 AM Info    ***AFTER***
    12:04:54 AM Info    summary: 2
    12:04:54 AM Info    etag: "3234758983260000"
    12:04:54 AM Notice  Execution completed
    
    • 注意Calendar.Events.get() 方法在Calendar.Events.patch() 执行之前执行了10 次。因此,您可以一次修补您的事件。
    • 我不是 Javascript Promises 方面的专家,但您可能希望删除 update()get()patch() 中的 async/await

    【讨论】:

    • 感谢您的回答,但我仍然无法理解为什么多个同时更新会相互覆盖。
    • 文档说如果事件自上次检索后发生变化,我将收到 412(前提条件失败)响应代码,但没有发生。
    • 它没有相互覆盖,发生的事情是您的 await 命令先执行了您的 events.get() 10 次,但没有继续执行您的 events.patch()。当 events.patch() 也被执行 10 次时,补丁请求中使用的 etag 是基于执行 10 次后的最后一个 events.get() 响应。它是基于示例复制代码得到证明的,并在日志中看到。
    • 您是否尝试过删除异步并等待以查看是否达到了预期的输出?
    • 我已经更新了我的示例代码,添加了像你这样的日志打印。此外,我还添加了代码的输出,我看到发生覆盖是因为日历 API 响应更新了 ETag。
    猜你喜欢
    • 2018-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-10
    • 1970-01-01
    • 2016-03-22
    • 2018-09-13
    • 1970-01-01
    相关资源
    最近更新 更多