Skip to content

drivers: do not exit the ttl fiber on an error - #266

Open
maksimuimin wants to merge 2 commits into
tarantool:masterfrom
maksimuimin:fix-ttl-fiber-errors
Open

maksimuimin wants to merge 2 commits into
tarantool:masterfrom
maksimuimin:fix-ttl-fiber-errors

Conversation

@maksimuimin

Copy link
Copy Markdown

Closes #263, related to #238

Based on #265 (the first commit is that PR); only the second commit is new here.

Problem

Any error inside a ttl iteration made the fiber return 1, leaving the dead fiber in self.fiber. So start() did nothing, ttl/ttr/delay processing stopped until the next ro -> rw switch, and for fifottl the next stop() blocked the queue state machine in ENDING forever. A user on_task_change callback raising once was enough to trigger it, see the repro in #263.

Fix

The fiber no longer exits on an unexpected error: it logs the error, backs off for one second and retries the iteration. Transient causes (a failed WAL write, a transaction conflict, a user callback) recover on their own; a persistent one is logged once per second instead of silently disabling ttl for the tube. The fiber still exits when it is cancelled or stopped (#265).

This also gives #238 a working answer: after stop() the fiber can always be brought back with start().

New test t/270-ttl-fiber-errors.t: a callback raising on ttl, the fiber survives, the next expired task is deleted, and an ro -> rw cycle brings the queue back to RUNNING. Full suite passes locally (Tarantool 3.8, memtx and vinyl).

Maxim Uymin and others added 2 commits September 22, 2026 15:18
fifottl and limfifottl used an unbuffered channel to stop the ttl
fiber, but the fiber read it only in ro mode. So stop() blocked
forever in rw mode and drop() did not stop the fiber at all, leaking
one fiber per dropped tube. utubettl used a buffered channel: stop()
returned, but the fiber kept running and crashed on the dropped space.

Now the fiber works while it is the fiber registered in the tube:
stop() deregisters it, wakes it up and joins it, and fifottl got a
drop() which stops the fiber before dropping the space. limfifottl
forwards start()/stop()/drop() to the parent driver so that the
registration lives in a single object.

Closes tarantool#262

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Any error inside a ttl iteration (a user on_task_change callback
raising, a transaction conflict, a failed WAL write) terminated the
ttl fiber for good: start() saw the dead fiber in self.fiber and did
nothing, so ttl/ttr/delay processing stopped until the next ro -> rw
switch, and with the unbuffered channel of fifottl stop() blocked the
queue state machine in ENDING forever.

Now the fiber logs the error, backs off for a second and retries the
iteration. It still exits when it is cancelled or stopped.

Closes tarantool#263
Part of tarantool#238

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

*ttl drivers: a dead TTL fiber cannot be restarted and wedges the queue in ENDING on the next RO switch

1 participant