Skip to content

SchedulerInitializer only registers one scheduler method per service (Map overwrite bug) #9

Description

@darkryh

Bug: SchedulerInitializer only registers one scheduler method per service

Summary

SchedulerInitializer discovers scheduler methods into a Map<Service, KFunction<*>>. When a service class exposes multiple valid scheduler methods, each discovered method overwrites the previous one for the same service key.

Result: only one scheduler method per service is validated and invoked.

Impact

This silently drops valid scheduled jobs when a service defines more than one SchedulerJobHandle registration method.

In a real backend integration, this caused:

  • scheduleStoryContinuityJobProcessor() to be registered and executed
  • scheduleEmbeddingReindexProcessor() (and other schedule methods in the same service) to never register

The queue stayed pending indefinitely (attempt_count=0, no execution logs), while other schedulers ran normally.

Affected code

katalyst-scheduler module

File: io/github/darkryh/katalyst/scheduler/lifecycle/SchedulerInitializer.kt

Current implementation:

  • discoverCandidateMethods(...) returns Map<Service, KFunction<*>>
  • discovery loop does candidates[service] = function

This overwrites previous methods for the same service.

Reproduction

  1. Create a service with 2+ methods that all:
  • return SchedulerJobHandle
  • have no required params
  • call scheduleCron / schedule / scheduleFixedDelay
  1. Start application with enableScheduler().
  2. Check scheduler initializer logs and runtime execution.

Expected

All valid scheduler methods across all services are discovered, validated, invoked, and registered.

Actual

Only one scheduler method per service is kept and registered.

Why this is risky

  • Silent partial initialization of critical background jobs
  • Operational drift (queues/backfills never processed)
  • Misleading startup signal (SCHEDULER PASSED) despite missing tasks

Proposed fix

1) Change candidate/validated collections to support multiple methods per service

Use one of:

  • List<Pair<Service, KFunction<*>>> (recommended for deterministic processing)
  • Map<Service, MutableList<KFunction<*>>>

2) Update all pipeline steps

  • discoverCandidateMethods
  • validateCandidatesByBytecode
  • invocation loop

to iterate all (service, method) pairs, not one method per service.

3) Improve diagnostics

At startup, log:

  • total candidate count
  • candidates grouped by service
  • final registered task names
  • skipped/failed methods explicitly

4) Add regression tests

Add tests that assert:

  1. Single service with multiple valid scheduler methods => all are registered.
  2. Multiple services each with multiple methods => all are registered.
  3. Mixed valid/invalid methods => only valid ones are registered, none overwritten.
  4. Invocation order is deterministic (if required by design).

Compatibility / migration

No API-breaking changes required if change is internal to SchedulerInitializer.

Suggested acceptance criteria

  • A service with N valid scheduler methods results in N registrations.
  • Scheduler summary and logs reflect full method set.
  • New tests fail on current implementation and pass after fix.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions