Skip to content

Conversation

@CodeDrivenMitch
Copy link
Collaborator

@CodeDrivenMitch CodeDrivenMitch commented Nov 18, 2025

Axon Framework 5 is out, and its configuration is fundamentally different. As such:

  • This module has been renamed to the Axoniq Platform client, formerly AxonIQ Console Framework client
  • The modules have been split similar to the modules of the framework, allowing users to not use a part of the framework
  • Aggregate support has been dropped
  • DLQ support has been dropped
  • Instrumentation now works via decorators instead of the SpanFactory mechanism, propagating its measurements via the ProcessingContext
  • Repository loads are now reported with the handler itself
  • The module is now activated by registering an AxoniqPlatformProperties object to the ComponentRegistry

Note that deleted code will be recovered from Git in the future when we re-implement it, for example the domain event stream feature. There were unknown classes and therefore could not be kept at this point in time.

Axon Framework 5 is out, and its configuration is fundamentally different. As such:

- This module has been renamed to the Axoniq Platform client, formerly AxonIQ Console Framework client
- The modules have been split similar to the modules of the framework, allowing users to not use a part of the framework
- Aggregate support has been dropped
- DLQ support has been dropped
- Instrumentation now works via decorators instead of the `SpanFactory` mechanism, propagating its measurements via the `ProcessingContext`
- Repository loads are now reported with the handler itself
- The module is now activated by registering an AxoniqPlatformProperties object to the ComponentRegistry
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces support for Axon Framework 5 with significant architectural changes. The module has been renamed from "AxonIQ Console Framework client" to "Axoniq Platform client" and refactored into multiple modules (messaging, modelling, eventsourcing). The instrumentation mechanism has been completely redesigned, moving from the SpanFactory pattern to decorators that propagate measurements via ProcessingContext. Aggregate and DLQ support have been removed, and the module is now activated by registering an AxoniqPlatformProperties object to the ComponentRegistry.

Key Changes:

  • Upgraded to Java 17, Axon Framework 5.0.0, Spring Boot 3.5.7, and Kotlin 2.2.20
  • Replaced SpanFactory-based instrumentation with decorator pattern using ProcessingContext
  • Split monolithic module into separate messaging, modelling, and eventsourcing modules
  • Removed aggregate and DLQ support functionality

Reviewed Changes

Copilot reviewed 122 out of 122 changed files in this pull request and generated no comments.

Show a summary per file
File Description
pom.xml Updated project coordinates, versions, and module structure for AF5 compatibility
axoniq-platform-client-messaging/* New core messaging module with decorator-based instrumentation
axoniq-platform-client-modelling/* New modelling module for repository instrumentation
axoniq-platform-client-eventsourcing/* New eventsourcing module for event storage engine instrumentation
axoniq-platform-client-spring-boot-starter/* Updated Spring Boot starter for simplified configuration
console-framework-client/* Removed old AF4-based implementation files

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +74 to +90
private fun waitForProcessorToHaveClaimedSegment(
processor: StreamingEventProcessor,
segmentId: Int,
): Boolean {
var loop = 0
while (loop < 300) {
Thread.sleep(100)
if (processor.processingStatus().containsKey(segmentId)) {
logger.debug("Processor [${processor.name()}] successfully claimed segment [$segmentId] in approx. [${loop * 100}ms].")
return true
}
loop++
}

logger.debug("Processor [${processor.name()}] failed to claim [$segmentId] in approx. [${loop * 100}ms].")
return false
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can use Awaitility lib here... Something like:

import org.awaitility.Awaitility.*
import java.time.Duration

private fun waitForProcessorToHaveClaimedSegment(
    processor: StreamingEventProcessor,
    segmentId: Int
): Boolean {
    return try {
        await()
            .atMost(Duration.ofSeconds(30))
            .pollInterval(Duration.ofMillis(100))
            .until { processor.processingStatus().containsKey(segmentId) }
        true
    } catch (e: Exception) {
        logger.debug("Processor [${processor.name()}] failed to claim [$segmentId]")
        false
    }
}

Copy link
Contributor

@stefanmirkovic stefanmirkovic Nov 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or alternatively, since we're using Kotlin, we can use coroutines, which don't block threads...
Something like:

suspend fun waitForProcessorToHaveClaimedSegment(
    processor: StreamingEventProcessor,
    segmentId: Int
): Boolean = withTimeout(30000) {
    while (!processor.processingStatus().containsKey(segmentId)) {
        delay(100)
    }
    true
}

or

suspend fun waitForProcessorToHaveClaimedSegment(
    processor: StreamingEventProcessor,
    segmentId: Int,
    maxAttempts: Int = 300
): Boolean {
    repeat(maxAttempts) { attempt ->
        if (processor.processingStatus().containsKey(segmentId)) {
            logger.debug("Processor [${processor.name()}] successfully claimed segment [$segmentId] after $attempt attempts")
            return true
        }
        delay(100)
    }
    logger.debug("Processor [${processor.name()}] failed to claim [$segmentId] after $maxAttempts attempts")
    return false
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want to add another dependency to this library. This adds extra code to the user base, and we should avoid that. Awaitility is usually a test dependency, and this might thus conflict.

As for Kotlin, I'd like to move away from this in the future (I can't believe I haven't done it now), as we had several conflicts with clients on versioning.

Copy link
Contributor

@stefanmirkovic stefanmirkovic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Really amazing work! 🙌 👏

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@CodeDrivenMitch CodeDrivenMitch merged commit 0c26899 into main Nov 26, 2025
2 of 3 checks passed
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.

2 participants