*ttl drivers: a dead TTL fiber cannot be restarted and wedges the queue in ENDING on the next RO switch
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 48/100
Direzione di ricerca
Start with queue/abstract/driver/fifottl.lua lines 164-167 and 415-427, then compare the buffered-channel behavior in utubettl. Run the reproduction in the issue and inspect queue_state handling during RO/RW switches. Done means a failed TTL iteration does not permanently disable processing or leave the queue stuck in ENDING, and start/stop remain safe.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Environment: queue master (07fd732), Tarantool 3.8.0 (also the same code in 1.5.0). memtx.
Related: #238 asks for an API to restart the TTL fiber. This issue is about what happens today when the fiber dies: it cannot be restarted, and for fifottl/limfifottl the queue state machine gets stuck in ENDING on the next RO switch, so the queue never comes back without an instance restart.
Summary
Any error inside a TTL iteration (a user on_task_change callback raising, an MVCC conflict, a vinyl read error, the nil dereference from the TTL branch, ...) makes the fiber return 1 (fifottl.lua#L164-L167) while self.fiber keeps pointing at the dead fiber. Consequences:
method.start()is a no-op becauseself.fiberis not nil (fifottl.lua#L415-L420). TTL/TTR/delay processing for the tube is dead.- On the next RO switch the state machine calls
stop(), which doesself.sync_chan:put(true)(fifottl.lua#L427). The channel is unbuffered and the only reader is dead (same root cause as #262), so thequeue_statefiber blocks forever. The queue stays inENDING, andput/takekeep failing withqueue is in ENDING stateeven after the instance is RW again.
For utubettl (buffered fiber.channel(1)) point 2 does not hang, but point 1 still holds until an RO->RW cycle.
Repro
local fiber = require('fiber')
box.cfg{}
local queue = require('queue')
local fired = false
local tube = queue.create_tube('t', 'fifottl', {
on_task_change = function(task, stat)
if stat == 'ttl' and not fired then
fired = true
error('user callback failed once')
end
end,
})
tube:put('a', {ttl = 0.1})
fiber.sleep(0.3)
print('1. fiber after one callback error:', tube.raw.fiber:status())
local b = tube:put('b', {ttl = 0.1})
fiber.sleep(0.3)
print('2. expired task still in space:', tube.raw.space:get(b[1]) ~= nil)
tube.raw:start()
print('3. fiber after start():', tube.raw.fiber:status())
box.cfg{read_only = true}
fiber.sleep(1)
print('4. queue.state() after RO switch:', queue.state())
box.cfg{read_only = false}
fiber.sleep(1)
print('5. queue.state() after RW switch:', queue.state())
print('6. put() after RW switch:', pcall(tube.put, tube, 'c', {ttl = 0.1}))
Output on master:
1. fiber after one callback error: dead
2. expired task still in space: true
3. fiber after start(): dead
4. queue.state() after RO switch: ENDING
5. queue.state() after RW switch: ENDING
6. put() after RW switch: true nil -- put() returns nil, log: "put: queue is in ENDING state"
Expected
A failed iteration should not permanently kill TTL processing: either the fiber survives the error (log it and continue / restart with backoff), or at least self.fiber is cleared on exit so start() can create a new one, and stop() must never block on a channel nobody reads.
Suggested fix
- Clear
self.fiberin a guaranteed cleanup path when the fiber exits (checking it still points to the current fiber). - Make
stop()tolerant of a dead fiber (checkself.fiber:status()or use a buffered channel /fiber:cancel()). - Optionally restart the fiber after an error with a backoff instead of
return 1; user callback errors could be pcall-ed inabstract.luaso a user bug cannot take the driver down.
- Lingua principale
- Lua
- Stelle
- 244
- Fork
- 56
- Merge medio
- 6g 8h
- PR unite (30g)
- 1
Guida per i contributori
Nessuna guida per i contributori indicizzata per questo repository
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di tarantool/queue
-
documentation good first issue
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 85/100
-
Difficoltà 3/5 1-2 giorni Idoneità per principianti 76/100
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 55/100
-
1sp bug teamE
Difficoltà 4/5 3-5 giorni Idoneità per principianti 25/100
-
bug
Difficoltà 4/5 3-5 giorni Idoneità per principianti 35/100
Tutte le issue di tarantool/queue
Issue simili
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
LandSandBoat/server#11579 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
ArchiveTeam/sinavideo-grab#7 · 3 reazioni ·
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
mailcow/mailcow-dockerized#7480 ·
-
mapper bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
-
documentation feature-request mini.completion
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 88/100