postgresql - Perl 中跨平台警报信号处理或执行超时最可靠的方法是什么?
问题描述
我使用Postgres 咨询锁和MySQL GET_LOCK()向Sqitch添加了咨询锁定。此功能可防止一次将多个 Sqitch 实例部署到数据库。这很好用,但我也想添加一个锁定超时,这样就永远不会发现 CI/CD 进程因为出现问题而挂起数小时或数天。
MySQLGET_LOCK()
支持超时参数,但 Postgres 咨询锁不支持。因为我认为其他数据库引擎也可能没有超时,所以我认为最好在 Perl 中实现超时。按照 DBI 手册,我使用Sys::SigAction来设置和处理超时:
# Try waiting for the lock.
require App::Sqitch::SigAction;
return $self->_locked(1) unless App::Sqitch::SigAction::timeout_call($wait, sub {
$self->wait_lock
});
我还添加了测试以确认它适用于 MySQL 和 Postgres。到目前为止,一切都很好。
唉, Sys::SigAction在 Windows 上不起作用。我试了一下并在 Windows 上对其进行了测试,但由于 Windows Perl 不是用Sys::SigAction 也需要d_sigaction
的 编译的,所以我没有走多远。我尝试实现Perl-standard / pattern,但在等待 Postgres 锁时无法发送信号。alarm
$SIG{ALRM}
这让我想到了我的问题:在 Perl 中超时某些执行的最佳跨平台模式是什么?理想情况下,它有一个直接的界面,可以在 *nix 和 Windows 上工作,并且可以有效地处理数据库查询的中断。
解决方案
在此处和其他地方的讨论之后,我最终放弃了 Sys::SigAction,而是切换到:
- 让数据库处理超时,就像 MySQL
get_lock()
一样 - 添加一个简单的轮询接口,带有指数退避和超时,引擎可以使用该接口轮询锁定而不是等待(类似于Retry::Backoff)
- 切换 Postgres 实现以使用 DBD::Pg 中的异步查询支持来发送锁定请求,并使用退避/超时接口检查它是否已返回,如果超时则取消查询
我特别高兴地意识到我可以做到#3,因为我最初使用超时/退避接口来轮询pg_try_advisory_lock( key )
,这感觉很重。最好异步调用pg_advisory_lock ( key )
和轮询它的响应。它看起来像这样:
sub wait_lock {
my $self = shift;
# Asyncronouslly request a lock with an indefinite wait.
my $dbh = $self->dbh;
$dbh->do(
'SELECT pg_advisory_lock(75474063)',
{ pg_async => DBD::Pg::PG_ASYNC() },
);
# Use _timeout to periodically check for the result.
return 1 if $self->_timeout(sub { $dbh->pg_ready && $dbh->pg_result });
# Timed out, cancel the query and return false.
$dbh->pg_cancel;
return 0;
}
当然MySQL 的实现更简单,因为get_lock()
所有的工作都完成了:
sub wait_lock {
my $self = shift;
$self->dbh->selectcol_arrayref(
q{SELECT get_lock('sqitch working', ?)},
undef, $self->lock_timeout
)->[0]
}
推荐阅读
- flutter - 如何将 Hive 对象(HiveList)列表存储/更新为 Hive 对象
- go - 扫描到 gorm 查询的结构
- typescript - 错误:找不到模块'@vue/cli-plugin-babel/preset'
- xml - 使用 Dart 修改 XML 文件
- c++ - Win32 API 示例代码给出编译错误“错误 C2065:'HINSTANCE':未声明的标识符”
- javascript - 为什么我在尝试安装软件包“npm install --save @fontawesome/free-brands-svg-icons”时收到错误消息
- reactjs - 使用useeffect和dispatch时react redux导致无限循环
- java - 嵌入式 Tomcat,如何用嵌入式 Tomcat 的新逻辑替换用于标准 Tomcat 的现有 web.xml
- shell - “-path ... -prune”的目的是什么?
- unit-testing - 如何使用 go mock-gen 模拟在 Golang usng echo 中为端点 url 编写单元测试?