Implementing Lifecycle Methods

Overview

Lifecycle methods allow you to hook into the Talon microservice lifecycle at specific points during startup, operation, and shutdown. The Talon runtime invokes these methods at well-defined stages, enabling you to:

  • Receive platform objects via dependency injection

  • Provide application objects for annotation scanning

  • Initialize resources and state

  • React to lifecycle transitions

  • Clean up resources during shutdown

Lifecycle methods fall into three categories:

Injection Methods

The Talon runtime invokes injection methods to provide your application with handles to platform objects. These methods are marked with @AppInjectionPoint and allow the runtime to inject objects like the AEP engine, message sender, and configuration descriptors.

Accessor Methods

The Talon runtime invokes accessor methods to gather application objects containing various annotations. These methods allow you to organize your code across multiple classes while making them discoverable to the Talon runtime.

Notification Methods

The Talon runtime invokes notification methods to notify your application of lifecycle transitions and operational events. These include initialization, finalization, and lifecycle event handlers.

See Also: Lifecycle - Complete lifecycle flow and timing


Dependency Injection

Use the @AppInjectionPoint annotation to receive platform objects from the Talon runtime.

Injectable Types

The Talon runtime can inject the following types:

Type
Purpose
Injection Timing

SrvAppLoader

Access to application and XVM configuration descriptors

Early in Open phase

AepEngineDescriptor

Modify engine configuration before creation

After HA policy determination

AepMessageSender

Send outbound messages

After engine creation

AepEngine

Access to running engine instance

After engine creation

Injection on Fields

You can inject directly into fields:

Injection on Methods

Alternatively, inject via setter methods for more control:

Injecting the Application Loader

The application loader provides access to configuration descriptors:

Modifying the Engine Descriptor

Inject the engine descriptor to programmatically configure the engine before it's created:

Timing: Engine descriptor injection occurs after the @AppHAPolicy is read but before the engine is created. Any HA policy set programmatically in the descriptor will override the annotation value.

See Also: AepEngineDescriptor Javadoc


Accessor Methods

Accessor methods allow you to provide objects to the Talon runtime for annotation scanning. This enables you to organize your code across multiple classes while keeping handlers, stats, and configuration discoverable.

Unified Accessor - @AppIntrospectionPoints

Use @AppIntrospectionPoints to provide objects for all types of annotation scanning:

When to Use: @AppIntrospectionPoints is called multiple times during the lifecycle (before configuration injection, command handler discovery, event handler discovery, etc.). This allows you to construct objects that depend on earlier lifecycle steps.

Fine-Grained Accessors

For large applications, use fine-grained accessors to reduce the number of objects scanned for each annotation type:

@AppConfiguredAccessor

Provide objects containing @Configured annotations:

@AppEventHandlerContainersAccessor

Provide objects containing @EventHandler methods:

@AppCommandHandlerContainersAccessor

Provide objects containing @Command methods:

@AppStatContainersAccessor

Provide objects containing @AppStat annotations:

Programmatic Event Handler

For advanced use cases, provide a programmatic event handler instead of using annotations:

See Also:


Initialization and Finalization

Application Initialization - @AppInitializer

The @AppInitializer method is invoked after the engine is created and injected but before it is started:

What's Available at Initialization:

  • βœ… Injected platform objects (engine, sender, etc.)

  • βœ… Configuration values

  • βœ… Application state factory has been provided

  • ❌ Engine is not yet started

  • ❌ Messaging is not yet connected

  • ❌ Store is not yet open

Thread Safety:

Application Finalization - @AppFinalizer

The @AppFinalizer method is invoked during shutdown after the engine is stopped:

What's Available at Finalization:

  • βœ… Injected platform objects still available

  • ❌ Engine is stopped

  • ❌ Messaging is disconnected

  • ❌ Store is closed

See Also: Lifecycle - Initialize Application


State Factory for State Replication

For State Replication microservices, provide the state factory via @AppStateFactoryAccessor:

See Also: State Replication Template


Synchronous Applications

Main Method - @AppMain

For microservices that are not event-driven (sender-only applications), implement a main method:

Execution:

  • Invoked in a separate thread after the engine becomes primary

  • Runs asynchronously from message processing

  • Suitable for driving application logic without inbound messages

When to Use: Use @AppMain for applications that generate messages or drive their own operation synchronously rather than reacting to inbound messages.

See Also: Lifecycle - Synchronous Applications


Handling Lifecycle Events

Use @EventHandler to react to lifecycle events dispatched by the Talon runtime.

Engine Lifecycle Events

AepEngineCreatedEvent

Dispatched after the engine is created but before it is started:

AepMessagingPrestartEvent

Dispatched before the engine attempts to connect to messaging:

AepEngineStartedEvent

Dispatched after the engine determines its role (primary or backup):

AepEngineActiveEvent

Dispatched when the engine becomes the active primary:

AepMessagingStartedEvent

Dispatched after messaging startup completes:

AepEngineStoppedEvent

Dispatched when the engine stops:

Messaging Lifecycle Events

AepChannelUpEvent

Dispatched when a channel connection is established:

AepChannelDownEvent

Dispatched when a channel connection is lost:

AepBusBindingUpEvent

Dispatched when a bus binding is fully operational:

Store Lifecycle Events (State Replication)

IStoreMemberUpEvent

Dispatched when a new member joins the store cluster:

IStoreMemberInitCompleteEvent

Dispatched when store initialization completes:

IStoreBindingRoleChangedEvent

Dispatched when the store binding's role changes:

Alert Events

Alert events signal exceptional conditions:

AepMessagingFailedEvent

AepBusBindingDownEvent

See Also: Events Reference - Complete event documentation


Complete Example

Here's a complete microservice demonstrating lifecycle method implementation:


Lifecycle Execution Order

Lifecycle methods are invoked in the following order during microservice startup:

Step
Annotation/Method
Purpose

1

Load main class

XVM loads the microservice

2

@AppInjectionPoint (SrvAppLoader)

Inject application loader

3

@AppHAPolicy

Read HA policy from annotation

4

@AppInjectionPoint (AepEngineDescriptor)

Inject engine descriptor for configuration

5

@AppConfiguredAccessor

Get objects for configuration injection

6

@Configured

Inject configuration values

7

@AppCommandHandlerContainersAccessor

Get command handler containers

8

@AppStatContainersAccessor

Get stat containers

9

@AppEventHandlerContainersAccessor

Get event handler containers

10

@AppStateFactoryAccessor

Get state factory (State Replication)

11

Create engine

Engine is instantiated

12

AepEngineCreatedEvent

Engine created event dispatched

13

@AppInjectionPoint (AepEngine, AepMessageSender)

Inject engine and sender

14

@AppInitializer

Initialize application

15

Start engine

Engine determines role and starts

16

AepEngineStartedEvent

Engine started event dispatched

17

AepEngineActiveEvent

Engine active event (if primary)

18

@AppMain

Main method invoked (if present)

During shutdown:

Step
Annotation/Method
Purpose

1

Stop engine

Engine stops processing

2

AepEngineStoppedEvent

Engine stopped event dispatched

3

@AppFinalizer

Finalize application

See Also: Lifecycle - Complete Flow


Best Practices

βœ… Do

  1. Use AepEngineActiveEvent for primary-only initialization

  2. Use @AppIntrospectionPoints for simple applications

    • Reduces boilerplate for small to medium applications

    • Single method to provide all objects

  3. Use fine-grained accessors for large applications

    • Improves startup performance by reducing object scanning

    • Better organization of handler containers

  4. Inject AepEngineDescriptor to configure the engine

  5. Use field injection for simplicity

    • Less code

    • Clear and concise

  6. Clean up resources in @AppFinalizer

❌ Don't

  1. Don't access microservice state in @AppInitializer (State Replication)

  2. Don't start background tasks in @AppInitializer

  3. Don't perform long-running operations in lifecycle methods

    • Keep initialization fast

    • Use background threads for heavy operations

  4. Don't assume messaging is ready in @AppInitializer

  5. Don't use @AppMain for event-driven applications

    • @AppMain is for sender-only applications

    • Event-driven apps should use @EventHandler

Thread Safety

  • Lifecycle methods are single-threaded: Only one lifecycle method executes at a time

  • Event handlers are single-threaded: Message processing is single-threaded by design

  • Background threads require synchronization: If you start background threads, ensure proper synchronization when accessing shared state

  • Volatile fields for stats: Use volatile for statistics accessed from background threads


See Also

Conceptual

Reference

How-To Guides

Templates

Last updated