Heroku 上多个数据库事务的原子性

发布于 2024-10-29 02:52:44 字数 587 浏览 0 评论 0原文

我的问题很简单,但我对 ruby​​ on Rails(以及网络编程)有点陌生,找不到好的答案。如何确保两个(或更多)数据库事务在 Heroku 上自动发生?

我可以像使用任何多线程应用程序一样使用互斥体对应用程序进行编码,并期望它在像 Heroku 这样的分布式服务器环境中正常工作吗?如果不是,确保两个或多个数据库事务原子性的最佳方法是什么?

我知道 Heroku 使用 PostgreSQL,它允许我获取一组数据库锁,但这些锁仅在一个事务中持续存在。此外,我熟悉用于同步多线程应用程序的互斥体(和 pthreads),但我不确定这些约定是否会在 Heroku 上按预期工作,特别是如果我的实际应用程序代码在多个服务器上运行的话。

编辑

我绝对应该解释一下我想要做的更多事情。我需要对数据库进行两次调用。第一个调用是读取布尔值。如果该布尔值是 true,我需要执行一些操作,如果它是 false,我需要执行其他操作。如果我读到 TRUE,那么我需要做一些其他的事情(与外部 API 的接口等...),如果成功,那么我需要将布尔值设置为 false。问题是我不知道如何避免多个客户端从数据库读取 true 的情况,而实际上,一个客户端正在写入 false 但尚未完成我之前需要做的其他事情写假。

My question's pretty simple, but I'm somewhat new ruby on rails (and web programming at that) and can't find a good answer. How do I ensure that two (or more) database transaction occur atomically on Heroku?

Can I code the application with mutexes, as I would any multi-threaded application, and expect it to work properly in a distributed server environment like Heroku? If not, what's the best way to ensure the atomicity of two or more database transactions?

I know Heroku uses PostgreSQL which lets me acquire an array of database locks, but these locks only persist for one transaction. Furthermore, I'm familiar with mutexes (and pthreads) to synchronize multi-threaded applications, but I'm not sure if these conventions will work as expected on Heroku, especially if my actual application code is running on multiple servers.

EDIT

I definitely should explain what I'm trying to do a little more. I need to make two calls to the database. The first call is a read of a boolean value. If that boolean value is true, I need to do some action, and if it is false I need to do something else. If I read a TRUE, then I need to do some other stuff (interface with external APIs etc...), and if that succeeds then I need to set the boolean to false. The problem is that I don't know how to avoid the situation where multiple clients read true from the database, when, in actuality, one client is en route to write false but hasn't yet completed the other stuff I need to do before writing false.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

放血 2024-11-05 02:52:44

这是一个可能可行的替代方案:

修改布尔字段以允许存储三态变量。 (日期/时间也可能很好,我稍后会解释一下。)

然后对操作进行编码,如下所示:

begin transaction
    read flag
    if true
         set flag to "processing" state
    if false
         perform other activity
commit

如果标志为 true,那么它现在将被设置为 processing< /代码>;调用外部 API,执行任何操作,然后知道结果:

begin transaction
    read flag
    if "processing"
        set flag to false
    if true
        warn loudly
    if false
        warn loudly
commit

当然,如果处理外部 API 的进程终止或阻塞太长时间,您会想知道并能够恢复。这就是为什么最好将日期/时间存储到标志中 - 如果它已处于 processing 状态六分钟,则终止它并重新启动。

使用 posix 信号量或类似工具会有一些好处,但我希望您的 Rails 后端进程可能每分钟都在不同的机器上执行。

Here's an alternative that might work:

Modify your boolean field to allow storing a tri-state variable. (Date/time might be nice too, I'll explain in a bit.)

Then code the operations like this:

begin transaction
    read flag
    if true
         set flag to "processing" state
    if false
         perform other activity
commit

If the flag was true, then it will now be set to processing; call the external API, do whatever, and when the results are known:

begin transaction
    read flag
    if "processing"
        set flag to false
    if true
        warn loudly
    if false
        warn loudly
commit

Of course, if the process handling the external API dies or blocks for too long, you'll want to know, and be able to recover. That's why it would be nice to store a date/time into the flag -- if it has been in the state processing for six minutes, then kill it and restart.

There would be something nice about using posix semaphores or similar tools, but I would expect your Rails backend processes might execute on different machines from minute to minute.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文