diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d78ba6d..bcab2a5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,27 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [Unreleased] + +- In replicaset mode, the behavior of the public API is reduced to the same behavior + in all queue states, including INIT. Previously, in the INIT state, an ambiguous + error was thrown when trying to access a public method on a replica and the script + was interrupted by an error. + + Old behavior (call `create_tube` on replica, queue is in INIT state): + ``` + 2023-09-04 14:01:11.000 [5990] main/103/replica.lua/box.load_cfg I> set 'read_only' configuration option to true + stack traceback: + /home/void/tmp/cluster/repl/queue/init.lua:44: in function '__index' + replica.lua:13: in main chunk + 2023-09-04 14:01:11.004 [5990] main/105/checkpoint_daemon I> scheduled next checkpoint for Mon Sep 4 15:11:32 2023 + 2023-09-04 14:01:11.004 [5990] main utils.c:610 E> LuajitError: /home/void/tmp/cluster/repl/queue/init.lua:45: Please configure box.cfg{} in read/write mode first + ``` + After this fix: + ``` + 2023-09-11 10:24:31.463 [19773] main/103/replica.lua abstract.lua:93 E> create_tube: queue is in INIT state + ``` + ## [1.3.2] - 2023-08-24 ### Fixed diff --git a/queue/init.lua b/queue/init.lua index f4f55222..40b9268c 100644 --- a/queue/init.lua +++ b/queue/init.lua @@ -1,3 +1,4 @@ +local abstract = require('queue.abstract') local queue_state = require('queue.abstract.queue_state') local queue = nil @@ -40,9 +41,18 @@ queue = setmetatable({ state = queue_state.show, cfg = deferred_cfg, _VERSION = require('queue.version'), -}, { __index = function() - print(debug.traceback()) - error('Please configure box.cfg{} in read/write mode first') +}, { __index = function(self, key) + -- In replicaset mode, the user can attempt to call public methods on the replica start. + -- For example, a single script is used for master and replica. + -- Each public method has a check on the state of the queue, so this forwarding is safe. + if deferred_opts['in_replicaset'] == true then + if abstract[key] ~= nil then + return abstract[key] + end + else + print(debug.traceback()) + error('Please configure box.cfg{} in read/write mode first') + end end }) diff --git a/t/200-master-replica.t b/t/200-master-replica.t index 5c078948..6cc709f2 100755 --- a/t/200-master-replica.t +++ b/t/200-master-replica.t @@ -24,7 +24,7 @@ local conn = {} test:plan(8) test:test('Check master-replica setup', function(test) - test:plan(8) + test:plan(9) local engine = os.getenv('ENGINE') or 'memtx' tnt.cluster.cfg{} @@ -41,6 +41,8 @@ test:test('Check master-replica setup', function(test) -- Setup tube. Set ttr = 0.5 for sessions expire testing. conn:call('queue.cfg', {{ttr = 0.5, in_replicaset = true}}) + test:isnil(conn:call('queue.create_tube', {'test', 'fifo'}), + 'check api call in INIT state') queue.cfg{ttr = 0.5, in_replicaset = true} local tube = queue.create_tube('test', 'fifo', {engine = engine}) test:ok(tube, 'test tube created')