每当更新数据库中的字段时调用外部API

时间:2017-07-26 08:44:49

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

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

public bool SubscribedToNewsletter { get;set; }

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

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

2 个答案:

答案 0 :(得分:1)

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

如果你这样做了,你会在持久更改数据库之前或之后调用API吗?如果之前:

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

    1. API可能不可用(例如停电)。你如何确保以后调用它以保持同步?
    2. 更新数据库后应用程序崩溃。如何确保API在重新启动时被调用?
    3. 有几种不同的方法可以解决这个问题。但是,请记住,通过同步到外部系统,您可能已经习惯了丢失了ACID语义,并且您的应用程序必须处理最终的一致性。

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

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

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

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

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

答案 1 :(得分:1)

我通常使用LISTENNOTIFY以及队列表解决此类问题。当感兴趣的更改时,您从触发器发送NOTIFY,并在队列表中插入一行。 LISTEN连接通知更改,从队列表中获取新行,对其进行操作,并将其标记为已完成。

而不是监听和通知你只能轮询一个队列表,监听和通知是一种优化。

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

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