Replies: 2 comments 1 reply
-
last_insert_id should be safe used on the same dbh that executed the statement. I don't suggest using state (instead of a lexical variable scoped to the startup method/lite application) as it will be executable-global and not application-global, but that shouldn't be relevant here either. DBIx::Connector is fork safe and will create a new connection in each fork. You may try using the preferred $db->run/$db->txn interface rather than retrieving a dbh from the connector. That said, I'm not fully versed in how last_insert_id works in DBD::Pg, which is described in some detail here: https://metacpan.org/pod/DBD::Pg#last_insert_id |
Beta Was this translation helpful? Give feedback.
-
Thank you for the insightful response and for confirming my understanding of However, i will switch to the Revised, Race-Condition-Safe Helper: helper insertDictIntoTable => sub {
my ($self, $table, $dict) = @_;
my $dbh = $self->db;
# Manually construct SQL to use the atomic RETURNING clause
my @cols = sort keys %$dict;
my $col_str = join ', ', map { qq{"$_"} } @cols; # Quote column names
my $ph_str = join ', ', ('?') x @cols;
my @bind = map { $dict->{$_} } @cols;
# The key change is adding "RETURNING id"
my $stmt = qq{INSERT INTO "$table" ($col_str) VALUES ($ph_str) RETURNING id};
# prepare -> execute -> fetch the returned ID
my ($new_id) = $dbh->selectrow_array($stmt, undef, @bind);
# selectrow_array returns the value directly
return $new_id;
}; This approach moves the logic of retrieving the ID from a separate, post-query DBI call into the atomic SQL query itself, which completely eliminates the possibility of a race condition. Thanks again for your help, which pointed me in the right direction to find the most robust solution. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi everyone,
I'm encountering a race condition in my Mojolicious application when using Minion workers to perform database inserts. It appears that
last_insert_id
is not reliably returning the ID for the insert performed by the current job, especially under load with multiple workers. I suspect this is due to how database connections are managed across the forked worker processes.My Setup:
state
variable.Relevant Code:
Database Connector Helper:
Generic Insert Helper:
Minion Task:
The Problem:
When multiple Minion workers execute this task concurrently, the
$new_id
returned byinsertDictIntoTable
is sometimes the ID generated by anINSERT
from a different worker. This leads to incorrect data processing.My question is: What is the recommended, race-condition-safe way to get the last inserted ID in a multi-worker Minion environment, specifically with PostgreSQL?
Is my
DBIx::Connector
setup withstate
appropriate for a pre-forking server like Minion, or is there a better pattern?Any advice would be greatly appreciated.
Thanks
Beta Was this translation helpful? Give feedback.
All reactions