Skip to content

Add UndecoratedRunnable to skip onSchedule decoration - #4339

Open
hocaron wants to merge 1 commit into
reactor:mainfrom
hocaron:4338-undecoratedRunnable
Open

hocaron wants to merge 1 commit into
reactor:mainfrom
hocaron:4338-undecoratedRunnable

Conversation

@hocaron

@hocaron hocaron commented Jul 26, 2026

Copy link
Copy Markdown

What

Adds UndecoratedRunnable, a marker interface for Runnable tasks that must be
submitted to a Scheduler without the decoration registered via
Schedulers.onScheduleHook(String, Function). Schedulers.onSchedule(Runnable)
now returns such tasks as-is.

Why

Library-internal, self-rescheduling maintenance tasks (resource eviction and the
like) never execute user code, yet they currently receive the same task decoration
as user tasks. With Hooks.enableAutomaticContextPropagation() enabled, that
decoration captures the scheduling caller's ThreadLocal state into the pending
task; because such tasks re-schedule themselves from inside the restored snapshot
scope, the captured request-scoped state is retained for the lifetime of the
resource (437MB observed in production — see #4338 and reactor/reactor-netty#4299).

There is no way to opt out today: every asynchronous Scheduler built via the
Schedulers factory methods funnels tasks through Schedulers.onSchedule(...).
reactor-netty had to hand-write a bypassing Scheduler in reactor/reactor-netty#4300;
reactor-pool's eviction task has the same shape and still affects direct
reactor-pool users. This marker gives libraries a first-class opt-out while
keeping the standard schedulers, including schedulers supplied by the user.

The name mirrors the existing NonBlocking thread marker in the same package.
Happy to rename or reshape the API if you prefer a different form.

Changes

  • New reactor.core.scheduler.UndecoratedRunnable marker interface (no methods).
  • Schedulers.onSchedule(Runnable) skips hook application for tasks implementing it.
    The added instanceof sits behind the existing hook != null short-circuit, so it
    only executes when a hook is registered, and is negligible next to the wrapper
    allocation it avoids (the class already type-checks similarly with
    Thread instanceof NonBlocking).
  • Tests in SchedulersHooksTest: a direct onSchedule unit test and a
    parameterized end-to-end test across PARALLEL / BOUNDED_ELASTIC / SINGLE /
    EXECUTOR_SERVICE / EXECUTOR verifying the hook is not applied to marked tasks.

User-facing tasks should not implement the marker (documented in the javadoc):
skipping decoration also skips user-registered hooks such as MDC propagation.

Fixes #4338.

@hocaron
hocaron requested a review from a team as a code owner July 26, 2026 15:04
Signed-off-by: hocaron <kkannu0407@gmail.com>
@hocaron
hocaron force-pushed the 4338-undecoratedRunnable branch from b9934ae to 3502eaf Compare July 26, 2026 15:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Provide a way for library-internal maintenance tasks to opt out of onSchedule decoration

1 participant