Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

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

オープン
#263 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
48/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
活発
技術スタック
lua
領域
backend

調査の方向性

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.

索引モデルが issue の本文から書いたものです。

説明

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:

  1. method.start() is a no-op because self.fiber is not nil (fifottl.lua#L415-L420). TTL/TTR/delay processing for the tube is dead.
  2. On the next RO switch the state machine calls stop(), which does self.sync_chan:put(true) (fifottl.lua#L427). The channel is unbuffered and the only reader is dead (same root cause as #262), so the queue_state fiber blocks forever. The queue stays in ENDING, and put/take keep failing with queue is in ENDING state even 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.fiber in a guaranteed cleanup path when the fiber exits (checking it still points to the current fiber).
  • Make stop() tolerant of a dead fiber (check self.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 in abstract.lua so a user bug cannot take the driver down.
主要言語
Lua
スター
244
フォーク
56
平均マージ
6日 8時間
マージ済み PR(30日)
1

コントリビューションガイド

このリポジトリのコントリビューションガイドは索引されていません

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

tarantool/queue のほかの issue

tarantool/queue の issue をすべて見る

似ている issue

Lua の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。