Skip to content

Fluxzero 1.185.0

Choose a tag to compare

@github-actions github-actions released this 25 May 07:14

1.185.0 (2026-05-25)

Features

  • feat(benchmark): add tracker preload mode (65a34f0)

    Replace the old publishMode/concurrentPublish switch with an explicit benchmark mode: PRELOAD, BULK, or CONCURRENT. PRELOAD publishes the event set before registering consumers so profiling can focus on post-publish drain behavior.

    Tests: ./mvnw -q -pl sdk -Dtest=TrackerIntegrationBenchmark test-compile

  • feat(benchmark): allow local tracker client mode (8f2a86e)

    Add a clientMode property to TrackerIntegrationBenchmark so it can run either against the default websocket/TestServer path or a shared LocalClient in-memory store.

    The local path intentionally reuses one root LocalClient across benchmark Fluxzero instances so default consumers and publishers observe the same message log.

    Tests: ./mvnw -q -pl sdk -am test-compile

    Tests: java -DclientMode=LOCAL -DclientCount=2 -DconsumerCount=3 -DthreadCount=1 -DmessageCount=50 -DpublisherCount=2 -DpublishBatchSize=5 -DpayloadBytes=0 -DbenchmarkTimeoutMs=10000 -cp ... io.fluxzero.sdk.benchmark.TrackerIntegrationBenchmark

Bug Fixes

  • fix(handling): guard reusable handler fast path (0340cca)

    Do not let generic delegating handlers expose reusable handler methods. Decorators that only override invoker resolution can otherwise be bypassed by the optimized DefaultTracking path.

    Add regression coverage for expired request filtering, websocket lifecycle decorators, protected data restoration, lazy payload selection, and error-reporting policy on reusable handler methods.

    Tests: ./mvnw -q -pl sdk -am -Dtest=ExpiredRequestDecoratorTest,WebsocketHandlerDecoratorTest,DataProtectionInterceptorTest,ErrorReportingInterceptorTest,PayloadParameterResolverTest -Dsurefire.failIfNoSpecifiedTests=false test

  • fix(handling): keep payload preparation lazy (84be102)

    Avoid reading serialized payloads while preparing payload parameter resolvers. Handler selection can use the serialized payload class, while actual payload deserialization remains deferred until the selected invoker resolves its argument.

    If a payload is already in memory or already deserialized, the resolver still reuses it for nullability checks. Chunked typed payloads remain lazy so selection does not wait for the final chunk.

    Tests: ./mvnw -q -pl sdk -am -Dtest=PayloadParameterResolverTest,ChunkedMessageTest#typedChunkedHandlerSelectionDoesNotBlockTrackerBeforeFinalChunk,DeserializingMessageTest -Dsurefire.failIfNoSpecifiedTests=false test

    Tests: ./mvnw -q -pl sdk -am test

  • fix(benchmark): isolate tracker clients per run (cd9602a)

    Give TrackerIntegrationBenchmark clients a run-specific id suffix derived from the namespace so TestServer command-idempotency results from a prior JVM cannot satisfy new append commands.

    Also log the namespace to make rerun diagnostics easier.

    Tests: ./mvnw -q -pl sdk -am test-compile

Performance Improvements

  • perf(tracking): trim batch handler overhead (4bac307)

    Reduce per-message tracking overhead by using an indexed list path for DeserializingMessage.forEachInBatch and by preparing payload parameters without repeating the payload cache lookup for regular non-chunked messages.

    Chunked typed payloads deliberately keep the old lazy resolver path so handler selection does not wait for the final chunk.

    Tests: ./mvnw -q -pl sdk -am -Dtest=ChunkedMessageTest#typedChunkedHandlerSelectionDoesNotBlockTrackerBeforeFinalChunk,PayloadParameterResolverTest,DeserializingMessageTest -Dsurefire.failIfNoSpecifiedTests=false test

    Tests: ./mvnw -q -pl sdk -am test

  • perf(handling): specialize single dynamic parameters (aec5079)

    Avoid allocating a Function[] and using the general IntFunction path for unvalidated handler methods with one dynamic parameter. This keeps the existing resolver matching semantics, but lets the hot payload-handler case call the single-argument member invoker directly.

    Tests: ./mvnw -q -pl common -Dtest=HandlerInspectorTest,HandlerInspectorParameterResolverTest test

    Tests: ./mvnw -q -pl sdk -am test

  • perf(serialization): avoid payload memoizer maps (caae69e)

    Use a single-value cache for the default Object.class payload lookup in DeserializingObject and keep the typed map only for explicit getPayloadAs lookups. This avoids per-message ConcurrentHashMap allocation in the common payload handler path.

    Tests: ./mvnw -q -pl sdk -am -Dtest=DeserializingMessageTest -Dsurefire.failIfNoSpecifiedTests=false test; ./mvnw -q -pl sdk -am test

  • perf(tracking): reduce batch filtering allocations (0a91eec)

    Replace hot stream and Optional-heavy tracking paths with direct loops for position checks, tracker filtering, and batch message handling while preserving the existing stream-based deserialize API.

    Tests: ./mvnw -q -pl common -Dtest=PositionTest,DefaultTrackingStrategyTest test; ./mvnw -q -pl sdk -am -Dtest=DeserializingMessageTest,ChunkedMessageTest -Dsurefire.failIfNoSpecifiedTests=false test; ./mvnw -q -pl sdk -am test

  • perf(reflection): specialize direct member invocation (77ccca1)

    Avoid creating per-call parameter-provider lambdas for the common no-arg and single-arg DefaultMemberInvoker paths while keeping the existing general IntFunction route for multi-arg and fallback invocation.

    Tests: ./mvnw -q -pl common -Dtest=DefaultMemberInvokerTest test; ./mvnw -q -pl sdk -am -Dtest=HandlerInspectorTest,ErrorReportingInterceptorTest,InvocationTest -Dsurefire.failIfNoSpecifiedTests=false test; ./mvnw -q -pl sdk -am test

  • perf(handling): reuse bound handler methods (7b7aed0)

    Split handler metadata into HandlerDescriptor and add a reusable HandlerMethod fast path for fixed-target single-method handlers. This keeps HandlerInvoker as the existing per-message compatibility adapter while allowing DefaultTracking and SDK-owned decorators to avoid per-message invoker and reporting wrapper allocation on eligible handlers.

    Also avoid an unused AtomicReference allocation in Invocation lazy id handling and cover the reusable method path in handler inspector and error reporting tests.

    Tests: ./mvnw -q -pl sdk -am test

  • perf(handling): reuse invokers as parameter providers (c46d646)

    Have unvalidated prepared and dynamic handler invokers implement IntFunction directly so invocation no longer creates an extra parameter-provider lambda. This preserves the same per-message invoker lifecycle while trimming one allocation layer from reflective handler dispatch.

    Tests: ./mvnw -q -pl sdk -am -Dtest=HandlerInspectorParameterResolverTest,TriggerParameterResolverTest,ThrowingErrorHandlerTest,TrackerIntegrationBenchmark,DefaultHandlerFactoryTest,HandlerMonitorTest -Dsurefire.failIfNoSpecifiedTests=false test; ./mvnw -q -pl sdk -am test

    JFR: local preload noop consumption showed the MethodHandlerMatcher lambda allocation disappear; remaining handler allocation is the per-message prepared invoker itself.

  • perf(handling): avoid handler policy cache hit allocations (b02c386)

    Avoid capturable loader lambdas on hot cache-hit paths in trigger filtering and error-reporting policy lookup. Trigger filters now also prepare to allowAll for methods without @​Trigger, removing that resolver from ordinary handler dispatch.

    Tests: ./mvnw -q -pl sdk -am -Dtest=TriggerParameterResolverTest,ThrowingErrorHandlerTest,TrackerIntegrationBenchmark,DefaultHandlerFactoryTest,HandlerMonitorTest -Dsurefire.failIfNoSpecifiedTests=false test; ./mvnw -q -pl sdk -am test

    JFR: local preload noop consumption completed in 1398 ms; TriggerMetadata and ErrorReportingInterceptor loader lambdas dropped out of the hot allocation sites, leaving prepared invoker allocation as the main handler-layer item.

  • perf(handling): reduce invocation threadlocal churn (482e5e0)

    Preserve the existing Invocation.getCurrent() semantics while avoiding ThreadLocal map remove churn for each top-level handler invocation. The new test pins that callbacks still run after the current invocation is cleared.

    Tests: ./mvnw -q -pl sdk -am -Dtest=InvocationTest,TrackerIntegrationBenchmark,DefaultHandlerFactoryTest,HandlerMonitorTest,ThrowingErrorHandlerTest -Dsurefire.failIfNoSpecifiedTests=false test; ./mvnw -q -pl sdk -am test

    JFR: local preload noop consumption completed in 1933 ms and removed ThreadLocalMap.set from the allocation top sites.

  • perf(handling): collapse no-op message filters (bdf06a0)

    Allow prepared message filters to identify always-true filters and collapse composed filter chains around them. Payload filters without allowed classes and segment filters without routing keys now disappear from the per-message hot path.

    JFR: /private/tmp/fluxzero-consumption-prepared-filter-noop.jfr no longer showed PayloadFilter/MessageFilter in the noop hot-method list; the run completed in 1320 ms.

    Tests: ./mvnw -q -pl sdk -am -Dtest=TrackerIntegrationBenchmark,DefaultHandlerFactoryTest,HandlerMonitorTest,ThrowingErrorHandlerTest -Dsurefire.failIfNoSpecifiedTests=false test

    Tests: ./mvnw -q -pl sdk -am test

  • perf(handling): reduce per-message invocation allocations (503849e)

    Skip building handler argument arrays when the method invocation validator is the default no-op validator. The validating path is preserved for web request parameter validation and custom validators.

    Reuse a completed report stage for handlers that do not need to send a response, avoiding a completed CompletableFuture allocation per event.

    JFR: /private/tmp/fluxzero-consumption-completed-report-noop.jfr no longer showed CompletableFuture.completedFuture in the allocation top; the noop handler run completed in 1594 ms.

    Tests: ./mvnw -q -pl sdk -am -Dtest=TrackerIntegrationBenchmark,DefaultHandlerFactoryTest,HandlerMonitorTest,ThrowingErrorHandlerTest -Dsurefire.failIfNoSpecifiedTests=false test

    Tests: ./mvnw -q -pl sdk -am test

  • perf(serialization): avoid optional allocation for first messages (b17c5a5)

    Add a nullable first-message deserialization path and use it from DefaultTracking and the benchmark raw deserialize pipeline. The existing Optional-returning API remains available and delegates to the nullable method.

    JFR: /private/tmp/fluxzero-consumption-nullable-serializer-deserialize.jfr showed Optional allocation pressure dropping in the deserialize-only profile, with wall-clock remaining in the same ~1.3s band.

    Tests: ./mvnw -q -pl sdk -am -Dtest=JacksonSerializerTest,TrackerIntegrationBenchmark,DeserializingMessageTest -Dsurefire.failIfNoSpecifiedTests=false test

    Tests: ./mvnw -q -pl sdk -am test

  • perf(handling): avoid optional allocation in invoker resolution (7bdf8aa)

    Add nullable invoker resolution methods alongside the existing Optional-based handler APIs and use them in the tracking hot path and core handler decorators. This keeps source compatibility while reducing per-message Optional churn through nested handlers and interceptors.

    JFR: /private/tmp/fluxzero-consumption-nullable-invoker-noop.jfr showed Optional.of allocation pressure dropping from roughly 6.6% to 3.8% in the noop handler profile; wall-clock remained noisy.

    Tests: ./mvnw -q -pl sdk -am -Dtest=DeserializingMessageTest,TrackerIntegrationBenchmark,ErrorReportingInterceptorTest,DefaultHandlerFactoryTest,HandlerMonitorTest,ThrowingErrorHandlerTest -Dsurefire.failIfNoSpecifiedTests=false test

    Tests: ./mvnw -q -pl sdk -am test

  • perf(serialization): memoize deserialized payloads lazily (45943f6)

    Delay creation of the memoizing payload wrapper until a deserializing object actually materializes or checks its payload. This removes memoizer allocation from tracking paths that only need serialized message metadata.

    Keep metadata copies sharing the same memoized payload function and cover that behavior with a focused regression test.

    Tests: ./mvnw -q -pl sdk -am -Dtest=DeserializingMessageTest,ObjectUtilsTest,TrackerIntegrationBenchmark -Dsurefire.failIfNoSpecifiedTests=false test

    Tests: ./mvnw -q -pl sdk -am test

  • perf(common): allocate memoization storage lazily (4c70f4c)

    Avoid creating a ConcurrentHashMap for memoized functions that are never evaluated. This reduces allocation pressure in deserializing message paths where payload functions are often carried through without materializing the payload.

    The Lombok-generated all-args constructor shape is retained explicitly for compatibility.

    Tests: ./mvnw -q -pl sdk -am test

  • perf(handling): cache static handler resolution (c3873d5)

    Prepare static parameter resolvers once per handler method so invocation no longer re-runs resolver matching for message, metadata, user, and timestamp parameters.

    Dynamic payload, trigger, and entity resolution remains message-dependent. Also cache error-reporting local-handler policy and skip request-expiry decoration for non-request handlers without changing public handler contracts.

    Tests: ./mvnw -B install

  • perf(handling): reduce tracking invocation overhead (8f7fd1c)

    Prepare message filters once per handler method, add first-message serializer and caster fast paths, and remove several per-message wrapper/allocation paths in tracking handlers.

    The serializer fast path preserves findAny semantics for split/drop upcasters and the message apply path keeps batch completion behavior covered by focused tests.

    Tests: ./mvnw -q -pl sdk -am -Dtest=HandlerInspectorTest,HandlerInspectorParameterResolverTest,HandlerInspectorSpecificityTest,ClientUtilsTest,DeserializingMessageTest,JacksonSerializerTest,UpcasterChainTest,ChunkedMessageTest,DataProtectionInterceptorTest,GivenWhenThenTest,GivenWhenThenRecursivePublicationGuardTest,HandlerInterceptorTest,ExpiredRequestDecoratorTest,StatefulHandlerTest -Dsurefire.failIfNoSpecifiedTests=false test

    Tests: ./mvnw -q -pl sdk -am test

    Tests: ./mvnw -B install

  • perf(tracking): reduce local in-memory tracking contention (efb0210)

    Reduce contention seen in local tracker profiling by replacing copy-on-write/synchronized hot-path structures, avoiding full-tail copies in the in-memory message store, and caching the local runtime client id.

    Keep DefaultTracking's non-chunked batch path eager and one-result-per-input so split upcasters cannot change tracking semantics while still avoiding chunk-specific bookkeeping for ordinary batches.

    Tests: ./mvnw -q -pl common -Dtest=InMemoryTaskSchedulerTest,DefaultTrackingStrategyTest test

    Tests: ./mvnw -q -pl sdk -Dtest=LocalTrackingClientTest,InMemoryMessageStoreTest,ChunkedMessageTest test

    Tests: ./mvnw -q -pl sdk -Dtest=ChunkedMessageTest,JacksonSerializerTest,UpcasterChainTest test

    Tests: git diff --check

Tests

  • test(benchmark): add consumption jfr option (b9a8fc9)

    Allow TrackerIntegrationBenchmark to start a programmatic JFR recording around the consumption phase only. This keeps publish/setup noise out of profiling runs while preserving the normal benchmark path when no jfrFile is configured.

    Tests: ./mvnw -q -pl sdk -am test

  • test(benchmark): add tracker pipeline modes (2b1c21f)

    Add pipelineMode variants to TrackerIntegrationBenchmark so LocalClient preload runs can isolate raw tracking, deserialization, direct handler invocation, annotated no-op handling, payload handling, and the existing benchmark handler.

    This keeps the existing benchmark defaults unchanged while making JFR comparisons between store/client, serializer, and handler pipeline costs repeatable.

    Tests: ./mvnw -q -pl sdk -am test