【问题标题】:Calling an external API whenever a field in the database is updated每当更新数据库中的字段时调用外部 API
【发布时间】:2017-07-26 08:44:48
【问题描述】:

我的ApplicationUser 模型包含一个属性:

public bool SubscribedToNewsletter { get;set; }

我想确保每当我在数据库中更新它的值时,都会调用一个外部 API 来从我的电子邮件自动化系统的列表中添加或删除用户,而无需自己手动调用该方法来确保同步程序员的意图。

ASP.NET 中是否提供了内置功能?还是我必须扩展UserManager 类并集中所有更新数据库的调用?

【问题讨论】:

  • 您的电子邮件自动化系统是什么?数据库中是否有一个表格,其中包含用户以及他们应该收到哪些新闻通讯的信息?如果是这样,那就很简单了
  • @user743414 这是活动监视器,但我不明白这与问题有何关系。是的,该表当然包含一个为每个用户提供该布尔值的列。

标签: c# postgresql model-view-controller asp.net-core


【解决方案1】:

调用外部 API 以与您的应用程序数据保持同步比在域模型中进行简单更改要复杂一些。

如果您这样做,您会在将更改持久化到数据库之前还是之后调用 API?如果之前:

  1. 如何确保数据库接受更改?
  2. 如果 API 调用失败怎么办?您拒绝更新数据库吗?
  3. 如果API调用成功但应用程序在更新DB之前崩溃或DB连接暂时丢失怎么办?

如果之后:

  1. API 可能不可用(例如中断)。您如何确保稍后调用它以保持同步?
  2. 更新数据库后应用程序崩溃。如何确保 API 在重新启动时被调用?

有几种不同的方法可以解决这个问题。但是,请记住,通过与外部系统同步,您可能已经失去了您可能习惯的 ACID 语义,您的应用程序将不得不处理最终的一致性。

一个简单的解决方案是使用另一个数据库表作为 API 调用队列(重要的是,这是按时间排序)。当用户的电子邮件更新时,您添加一行作为数据库事务的一部分,其中包含所需的相关详细信息。这可确保调用 API 的请求始终与更新一起记录。

然后你会有一个单独的进程(或线程)来轮询这个表。您可以使用pg_notify 来支持推送通知而不是轮询。

这个过程可以(按顺序)读取行,然后调用相关的 API 在外部系统中进行更改。如果成功,它可以删除该行。如果失败,它可以使用指数回退再次尝试。应记录持续的故障以供调查。

现在最糟糕的情况是您有 至少一次 传递语义来更新系统(例如,如果 API 调用成功但进程在删除行之前崩溃,那么将再次进行调用当进程重新启动时)。如果您需要at-most-once,您可以在尝试拨打电话之前删除该行。

这显然掩盖了一些细节,需要针对高吞吐量系统进行修改,但希望能解释一些原则。

【讨论】:

    【解决方案2】:

    我通常用LISTENNOTIFY 加上一个队列表来处理这类事情。当兴趣发生变化时,您从触发器发送NOTIFY,并将一行插入到队列表中。 LISTENing 连接注意到更改,从队列表中获取新行,对其进行操作,并将它们标记为已完成。

    您可以只轮询队列表,而不是监听和通知,监听和通知是一种优化。

    为了使这个可靠,要么你采取的行动必须在同一个数据库中并在与队列更新相同的连接上完成,或者你需要使用两阶段提交来同步行动。这超出了此类答案的范围,因为您需要用于崩溃恢复等的事务解析器。

    如果多次调用 API 是安全的(它是幂等的),那么在操作中途失败时,只需在崩溃恢复/重新启动/等时再次执行挂起的队列表中的所有条目就可以了。如果您不能安全地重复其中一项操作,您通常只需要 2PC 等。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-12
      • 2016-08-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-11
      • 1970-01-01
      相关资源
      最近更新 更多