Class MultiTenantStreamingProcessorRestarter

java.lang.Object
io.axoniq.framework.messaging.multitenancy.configuration.MultiTenantStreamingProcessorRestarter
All Implemented Interfaces:
DescribableComponent

@Internal public class MultiTenantStreamingProcessorRestarter extends Object implements DescribableComponent
Restarts the running StreamingEventProcessors whenever the set of tenants changes, so a processor streaming across tenants re-opens its stream with the current tenants.

A running stream cannot change its set of tenants. The merged stream is assembled over the tenants present when it opened, so a tenant added afterwards is not read and a removed tenant's stream stays open. Re-opening the stream with the current tenants requires a processor restart, which the coordinator supports.

The restart follows the MultiTenantEventStorageEngine handed to follow(MultiTenantEventStorageEngine) at startup, rather than the TenantProvider that engine itself follows. A tenant change reaches the provider's subscribers in turn, and a subscriber ahead of the engine may take real time over its own registration, such as one opening a connection for the tenant. A restart takes barely any time by comparison, so a restart driven by the provider can re-open the stream while the engine still reports the previous tenants. The new tenant is then missing from a stream that nothing re-opens again, because no further tenant change follows. Following the engine rules that out: it announces a change only once that change is visible through its own tenants.

Restarts are coalesced onto a single thread: a burst of tenant changes, such as the initial discovery of several tenants, results in as few restarts as possible while still ending on the current tenant set. Every restart pauses processing for all tenants briefly. Whether the tenants discovered at startup request a restart depends on whether this restarter subscribed before they were registered, which is not fixed. Either way the processors start far later in the lifecycle, so such a request finds nothing running and each processor opens its stream over the full startup set of its own accord.

Every running streaming event processor is restarted, not only the ones consuming across tenants. With the module on the classpath multi-tenancy is on by default, so the event store routes across tenants and a pooled streaming processor consumes them all. Restarting a processor that reads another source is harmless. It re-opens its own source. Restarting only the multi-tenant processors would require inspecting each processor's configured source, which the processor API does not expose, and tenant changes are infrequent, so restarting all of them is the simpler and safe choice.

Each processor's shutdown-and-start is bounded by a safety-net timeout, so a processor that never completes its shutdown or start cannot block the restart thread. It is taken from the MultiTenantStreamingProcessorRestartConfiguration, which defaults to 30 seconds. A deployment whose processors are slow to stop and start can register a customized MultiTenantStreamingProcessorRestartConfiguration to raise it.

Internal, because it is registered by the MultiTenancyConfigurationDefaults enhancer. The only member an enhancer building a tenant-routing engine calls is follow(MultiTenantEventStorageEngine).

Since:
5.3.0
Author:
Laura Devriendt
  • Method Details

    • follow

      @Internal public void follow(MultiTenantEventStorageEngine engine)
      Follows the tenant changes of the given engine, whose tenants decide what a re-opened stream spans.

      Must be called with the engine an enhancer built, from a start handler on that engine's own component definition, rather than with one resolved from the Configuration. The engine is registered under EventStorageEngine and any enhancer may decorate that type, so a resolved instance can be a decorator, which announces no tenant change at all.

      May be called before or after start(), since a change announced while this restarter is not running is ignored. Only one engine can be followed, since a second one's tenants decide nothing about the merged stream the first one spans.

      Parameters:
      engine - the engine whose tenant changes re-open the streams of the running streaming event processors
      Throws:
      NullPointerException - if the given engine is null
      AxonConfigurationException - if this restarter already follows an engine
    • describeTo

      public void describeTo(ComponentDescriptor descriptor)
      Description copied from interface: DescribableComponent
      Describe the properties of this DescribableComponent with the given descriptor.

      Components should call the appropriate describeProperty methods on the descriptor to register their properties. The descriptor is responsible for determining how these properties are formatted and structured in the final output.

      Best Practices: As a general rule, all relevant fields of a DescribableComponent implementation should be described in this method. However, developers have discretion to include only the fields that make sense in the context. Not every field may be meaningful for description purposes, especially internal implementation details. Furthermore, components might want to expose different information based on their current state. The final decision on what properties to include lies with the person implementing the describeTo method, who should focus on providing information that is useful for understanding the component's configuration and state.

      Example implementation:

       public void describeTo(ComponentDescriptor descriptor) {
           descriptor.describeProperty("name", this.name);
           descriptor.describeProperty("enabled", this.enabled);
           descriptor.describeProperty("configuration", this.configuration); // A nested component
           descriptor.describeProperty("handlers", this.eventHandlers);      // A collection
       }
       
      Specified by:
      describeTo in interface DescribableComponent
      Parameters:
      descriptor - The component descriptor to describe this DescribableComponentn its properties in.