This is an automated email from the ASF dual-hosted git repository. vatamane pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/couchdb.git
commit c6c5ba465b8a95f17d62a3037b265beca90587d7 Author: Nick Vatamaniuc <[email protected]> AuthorDate: Fri Sep 26 17:58:47 2025 -0400 Reschedule scanner plugins if they return skip on start or resume Previously, if a plugin returned `skip` on `start/2` or `resume/2`, then the plugin would stop and it wouldn't be scheduler to run again, even if it has a "repeat" time interval set. The new behavior on `skip` is to schedule the plugin to run again if plugin is configured to repeat it's execution. This way, a plugin may react to a temporary condition (feature disabled, some missing or crashed dependency) with a `skip`, and then it will get a chance to retry later hoping the conditions will change and it will continue executing. --- src/couch_scanner/src/couch_scanner_plugin.erl | 29 ++++++++++++++++------ .../test/eunit/couch_scanner_test.erl | 20 +++++++++++++++ 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/couch_scanner/src/couch_scanner_plugin.erl b/src/couch_scanner/src/couch_scanner_plugin.erl index 1ea6d57e4..0454a6d59 100644 --- a/src/couch_scanner/src/couch_scanner_plugin.erl +++ b/src/couch_scanner/src/couch_scanner_plugin.erl @@ -246,7 +246,7 @@ init_from_checkpoint(#st{} = St) -> <<"start_sec">> := StartSec } -> Now = tsec(), - PSt = resume_callback(Cbks, SId, EJsonPSt), + PSt = resume_callback(Mod, Cbks, SId, EJsonPSt), St#st{ pst = PSt, cursor = Cur, @@ -502,20 +502,33 @@ start_callback(Mod, Cbks, Now, ScanId, LastStartSec, #{} = EJson) when TSec when is_integer(TSec), TSec =< Now -> #{start := StartCbk} = Cbks, case StartCbk(ScanId, EJson) of - {ok, PSt} -> PSt; - skip -> exit_resched(infinity); - reset -> exit_resched(reset) + {ok, PSt} -> + PSt; + skip -> + % If plugin skipped start, count this as an attempt and + % reschedule to possibly retry in the future. + SkipReschedTSec = schedule_time(Mod, Now, Now), + exit_resched(SkipReschedTSec); + reset -> + exit_resched(reset) end; TSec when is_integer(TSec), TSec > Now -> exit_resched(TSec) end. -resume_callback(#{} = Cbks, SId, #{} = EJsonPSt) when is_binary(SId) -> +resume_callback(Mod, #{} = Cbks, SId, #{} = EJsonPSt) when is_binary(SId) -> #{resume := ResumeCbk} = Cbks, case ResumeCbk(SId, EJsonPSt) of - {ok, PSt} -> PSt; - skip -> exit_resched(infinity); - reset -> exit_resched(reset) + {ok, PSt} -> + PSt; + skip -> + % If plugin skipped resume, count this as an attempt and + % reschedule to possibly retry in the future + Now = tsec(), + SkipReschedTSec = schedule_time(Mod, Now, Now), + exit_resched(SkipReschedTSec); + reset -> + exit_resched(reset) end. db_opened_callback(#st{pst = PSt, callbacks = Cbks, db = Db} = St) -> diff --git a/src/couch_scanner/test/eunit/couch_scanner_test.erl b/src/couch_scanner/test/eunit/couch_scanner_test.erl index 1fe2e157d..d288dc50a 100644 --- a/src/couch_scanner/test/eunit/couch_scanner_test.erl +++ b/src/couch_scanner/test/eunit/couch_scanner_test.erl @@ -29,6 +29,7 @@ couch_scanner_test_() -> ?TDEF_FE(t_conflict_finder_works, 30), ?TDEF_FE(t_config_skips, 10), ?TDEF_FE(t_resume_after_error, 10), + ?TDEF_FE(t_resume_after_skip, 10), ?TDEF_FE(t_reset, 10), ?TDEF_FE(t_schedule_repeat, 10), ?TDEF_FE(t_schedule_after, 15) @@ -272,6 +273,25 @@ t_resume_after_error(_) -> config:set("couch_scanner_plugins", Plugin, "true", false), meck:wait(?FIND_PLUGIN, resume, 2, 10000). +t_resume_after_skip(_) -> + meck:reset(?FIND_PLUGIN), + meck:expect( + ?FIND_PLUGIN, + start, + 2, + meck:seq([ + skip, + meck:passthrough() + ]) + ), + Plugin = atom_to_list(?FIND_PLUGIN), + config:set("couch_scanner", "min_penalty_sec", "1", false), + config:set("couch_scanner", "interval_sec", "1", false), + config:set(Plugin, "repeat", "2_sec", false), + couch_scanner:resume(), + config:set("couch_scanner_plugins", Plugin, "true", false), + meck:wait(?FIND_PLUGIN, complete, 1, 10000). + t_reset(_) -> meck:reset(?FIND_PLUGIN), meck:expect(
