谷歌日历 API。同时修补事件时修改丢失

Posted

技术标签:

【中文标题】谷歌日历 API。同时修补事件时修改丢失【英文标题】:Google calendar API. Modifications loss when simultaneously patching event 【发布时间】: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

【问题讨论】:

【参考方案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。

以上是关于谷歌日历 API。同时修补事件时修改丢失的主要内容,如果未能解决你的问题,请参考以下文章

谷歌日历API v3从timeMin之前的全天活动

如何传播通过 gdata python api 创建的谷歌日历事件的提醒?

如何使用 android 使用日历 API 在谷歌日历上添加事件?

ios 添加事件到谷歌日历

使用谷歌日历的谷歌数据 API 创建新活动时向客人发送电子邮件

如何从单个谷歌帐户的多个谷歌日历中获取所有事件?