Ik ken knex niet in detail en uit een snelle zoekopdracht ondersteunt knex momenteel het gebruik van "limiet" op update-statements niet, dus slechts een beschrijving van de algemene aanpak.
Voer eerst een update uit voor de rij die aan de criteria voldoet en selecteer vervolgens die bijgewerkte rij.
Voer dus eerst een updatebewerking uit die de huidige gebruikers-ID toewijst aan de eerste onverwerkte rij waaraan ofwel geen gebruiker is toegewezen of waaraan al dezelfde gebruiker is toegewezen:
update rows
set assignedTo = user.id
where assignedTo=0 or assignedTo=user.id
order by createdAt asc
limit 1
Ik denk dat het zo kan werken met knex met een onbewerkte query, maar ik heb dat niet geprobeerd:
await knex.raw('update rows set assignedTo = :userid where assignedTo=0 or assignedTo= :userid order by createdAt asc limit 1', {userid: user.id})
Dit zoekt naar de eerste (vroegst aangemaakteAt) rij die niet is toegewezen of al is toegewezen aan dezelfde gebruiker en wijst vervolgens die gebruiker toe. Dit gebeurt in één keer.
U kunt dan zoeken naar de rij die aan de gebruiker is toegewezen:
const notProcessed = await knex('rows')
.select('*'')
.whereRaw(`status='Not-Processed' and assignedTo=${user.id}`)
.orderByRaw('createdAt asc')
.first();
Merk op hoe we nu expliciet alleen zoeken naar een rij die al aan de gebruiker is toegewezen.
Gecombineerd
await knex.raw('update rows set assignedTo = :userid where assignedTo=0 or assignedTo= :userid order by createdAt asc limit 1', {userid: user.id})
const notProcessed = await knex('rows')
.select('*'')
.whereRaw(`status='Not-Processed' and assignedTo=${user.id}`)
.orderByRaw('createdAt asc')
.first();
Uiteraard heb je de select niet nodig als je niet meteen met de rij wilt werken.
Het probleem is dat wanneer meerdere verzoeken tegelijkertijd worden afgehandeld, u zich moet voorstellen dat meerdere exemplaren van de code tegelijkertijd parallel lopen. Dus met uw originele code kunnen twee verzoeken uw selectie tegelijkertijd uitvoeren voordat een van hen een update uitvoert. Dus beide krijgen dezelfde rij terug.
Door de rij binnen de instructie onmiddellijk bij te werken, zelfs wanneer twee instructies parallel lopen, zorgt de database ervoor dat ze niet dezelfde rij zien.
Een alternatieve benadering voor een oplossing zou zijn om een mutex te gebruiken (zoals bijvoorbeeld async-mutex ) rond uw oorspronkelijke code om ervoor te zorgen dat uw oorspronkelijke selectie- en updatebewerking atomair is (gebeurt in één keer), maar dit zal hoogstwaarschijnlijk de responstijd van uw toepassing verlengen, omdat in sommige situaties de ene aanvraagverwerkingsbewerking op een andere moet wachten één om door te gaan.