尝试从 Rails (7.0.8) 开发环境中的 Sidekiq (7.2.1) 作业中的块中挽救
PG::UniqueViolation
错误,在 Ubuntu 20.04 上使用本地 PostgreSQL 14.10 db 在 Ruby 3.2.2 修订版 e51014f9c0 上运行时失败。我在测试时使用 InitThingsJob.new.perform_now
从控制台启动该作业,并在第一个位置有一个已知的重复项。
尝试
rescue ActiveRecord::RecordNotUnique
或 rescue PG::UniqueViolation, ActiveRecord::RecordNotUnique
同样会失败。
失败的函数对从包含对象集合的外部 API 接收到的响应进行操作。有时,但很少见的是,外部 API 具有重复的条目。我们不能拥有这些,因此数据库在可靠的 id 字段上有一个唯一索引。
它的目的是从响应中的集合创建一个数组,然后在块中迭代该数组并创建每个元素的记录。如果从一个元素成功创建了一个元素,那么它会移动数组以删除该元素。如果出现
PG::UniqueViolation
错误,则会挽救该错误,移动数组以删除导致错误的元素,并使用截断的数组重试该块。
def create_x_from_y_query
response_objs = @response.body["data"]["objects"]
begin
response_objs.each do |obj|
@obj = Obj.new(k_id: obj["k_id"], etc: obj["etc"])
@obj.save
#... other things...
response_objs.shift
end
rescue PG::UniqueViolation
logger.warn "Warning stuff."
response_objs.shift
retry
end
end
预期的行为是挽救
PG::UniqueViolation
错误,移动产生错误的可枚举元素,然后使用截断的数组重试该块。
当遇到重复项时,作业会因错误
PG::UniqueViolation
退出,返回:
E, [2024-01-23T13:57:36.755697 #1213779] ERROR -- : Error performing InitThingsJob (Job ID: 1312b3a9-8359-4cb6-a16d-8442370d815b) from Sidekiq(default) in 1548.0ms: ActiveRecord::RecordNotUnique (PG::UniqueViolation: ERROR: duplicate key value violates unique constraint "index_obj_on_k_id"
DETAIL: Key (k_id)=(<value>) already exists.
):
/home/xxx/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/activerecord-7.0.8/lib/active_record/connection_adapters/postgresql_adapter.rb:768:in `exec_params'
... Down the trace until we arrive at:
/home/xxx/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/activerecord-7.0.8/lib/active_record/connection_adapters/postgresql_adapter.rb:768:in `exec_params': PG::UniqueViolation: ERROR: duplicate key value violates unique constraint "index_obj_on_k_id" (ActiveRecord::RecordNotUnique)
DETAIL: Key (k_id)=(<value>) already exists.
/home/xxx/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/activerecord-7.0.8/lib/active_record/connection_adapters/postgresql_adapter.rb:768:in `exec_params': ERROR: duplicate key value violates unique constraint "index_objs_on_k_id" (PG::UniqueViolation)
DETAIL: Key (k_id)=(<value>) already exists.
对处理事务内唯一约束异常的一些回复表明,他们的问题是由并发引起的,并在事务块之外处理救援来解决它或救援ActiveRecord错误而不是PG错误,但在这里似乎都不起作用,并且错误输出不一样。