Class PushEngine
- All Implemented Interfaces:
IPushNotificationEngine
Concurrency. Sends run on a virtual-thread-per-task executor, unbounded by construction; the hard ceiling on notifications in flight is a Semaphore sized to IPushSettings.getMaxParallelPush(), acquired before every dispatch and released on completion. The setting is read once at start and held.
A send builds its RoutingPlan first (the audit record, the authorization check and the area filter all happen there, before anything leaves), then dispatches every target of every slice under a permit, records one outcome per target and completes the future with the PushResultImpl. A device target goes to its transport; an in-session target to the IInSessionDelivery seam, with the ruled fallback: when the app session closed holding the notification, a device push from this same server.
Failures become spool entries. A transient transport failure spools the notification for that target with exponential backoff; a replay loop on its own virtual thread sends due entries, re-resolving each subscription so a re-registered device is reached at its new endpoint, and persists the spool after each pass and at shutdown.
Single server. Every slice is local; the region tree names regions for the audit record and the area filter and never routes remotely. Nothing changes in the interfaces when that arrives.
- Author:
- Christopher Mindus
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final classThe collaborators of an engine, so that a test can build one without a server.Constructor Summary
ConstructorsMethod Summary
Modifier and TypeMethodDescriptionvoiddispose()Disposes the engine: transitions throughPushEngineState.STOPPINGtoPushEngineState.STOPPED, refusing new sends, allowing in-flight sends to complete, persisting the spool, and releasing the executor and transports.Gets the application configurations.intGets the number of sends in flight now.intGets the ceiling the engine started with.Gets the region tree the router resolves residency against.Gets the resolver.--- Accessors ---getSpool()Gets the spool.getState()Gets the current lifecycle state of the engine.getStore()Gets the store.getTransport(PushTransport kind) Gets a transport.getUsers()Gets the user directory.booleanReports whether the engine has been disposed.Creates a new, empty message builder bound to this engine, so that defaults such as TTL are taken from this engine's settings.planSend(IPushSendRequest request) --- Planning and sending ---send(IPushSendRequest request, IPushProgressListener progress) Performs a send asynchronously.sendToUsers(String appId, String topic, long[] uids, IPushNotification message) Sends a notification to users by ID for an application and Topic, with the server's default policies and an unrestricted operator, and waits a bounded time.static FilespoolFile(IPushSettings settings, File serverDir) Gets the default spool file of a server:<spoolDirectory>/pnspool.xml, the spool directory being the setting when non-empty, elsepush-spoolunder the server's current directory.voidstart()Starts the engine: creates the ceiling and the executor, ensures the schema, loads the spool and starts the replay loop.
Constructor Details
PushEngine
Constructor. Nothing runs untilstart().- Parameters:
cfg- The collaborators; settings, store, users, configs and spool are required.
Method Details
start
Starts the engine: creates the ceiling and the executor, ensures the schema, loads the spool and starts the replay loop.- Throws:
IllegalStateException- If the engine is not inPushEngineState.NOT_STARTED.SQLException- If the subscription table cannot be created or migrated.
getState
Description copied from interface:IPushNotificationEngineGets the current lifecycle state of the engine.- Specified by:
getStatein interfaceIPushNotificationEngine- Returns:
- The state; never
null.
isDisposed
public boolean isDisposed()Description copied from interface:IPushNotificationEngineReports whether the engine has been disposed.A disposed engine is in
PushEngineState.STOPPEDand performs no further work; the next access to the service creates a fresh engine rather than reviving this one.- Specified by:
isDisposedin interfaceIPushNotificationEngine- Returns:
trueif this engine has been disposed.
dispose
public void dispose()Description copied from interface:IPushNotificationEngineDisposes the engine: transitions throughPushEngineState.STOPPINGtoPushEngineState.STOPPED, refusing new sends, allowing in-flight sends to complete, persisting the spool, and releasing the executor and transports. Idempotent — disposing an already-disposed engine has no effect.- Specified by:
disposein interfaceIPushNotificationEngine
getSettings
--- Accessors ---- Specified by:
getSettingsin interfaceIPushNotificationEngine- Returns:
- The settings; never
null.
getRegionTree
Description copied from interface:IPushNotificationEngineGets the region tree the router resolves residency against.- Specified by:
getRegionTreein interfaceIPushNotificationEngine- Returns:
- The region tree; never
null.
newMessageBuilder
Description copied from interface:IPushNotificationEngineCreates a new, empty message builder bound to this engine, so that defaults such as TTL are taken from this engine's settings.- Specified by:
newMessageBuilderin interfaceIPushNotificationEngine- Returns:
- A fresh
IPushNotificationMessageBuilder; nevernull.
getStore
getUsers
getConfigs
getResolver
getSpool
getTransport
Gets a transport.- Parameters:
kind- The kind.- Returns:
- The transport, or null when the engine has none of that kind.
getMaxParallel
public int getMaxParallel()Gets the ceiling the engine started with.- Returns:
- The maximum in flight.
getInFlight
public int getInFlight()Gets the number of sends in flight now.- Returns:
- The in-flight count.
planSend
--- Planning and sending ---- Specified by:
planSendin interfaceIPushNotificationEngine- Parameters:
request- The send request (filter, notification, policies, authorization context).- Returns:
- The routing plan that a real send of this request would follow.
- Throws:
PushAuthorizationException- if the request's operator is not authorized for a region the plan requires.
send
Description copied from interface:IPushNotificationEnginePerforms a send asynchronously.Builds the routing plan, checks authorization, then dispatches each region slice — local slices through this server's send path, remote slices to the region's server over the server-to-server channel — acquiring a concurrency permit per dispatch so the in-flight count never exceeds
IPushSettings.getMaxParallelPush(). Unreachable regions and unreachable endpoints spool. The returned future completes when every slice has been resolved, with aPushResultthat carries the routing plan and the per-target, per-region, per-tier outcomes.To wait a bounded time for completion, call
future.get(timeout, unit)on the result — the framework's completion handle is a standardCompletableFuture.- Specified by:
sendin interfaceIPushNotificationEngine- Parameters:
request- The send request.progress- An optional progress callback invoked as slices complete, for bulk sends; may benull.- Returns:
- A future completing with the aggregate
PushResult.
sendToUsers
public PushResultImpl sendToUsers(String appId, String topic, long[] uids, IPushNotification message) throws Exception Sends a notification to users by ID for an application and Topic, with the server's default policies and an unrestricted operator, and waits a bounded time.- Parameters:
appId- The application ID,*for every application.topic- The Topic, empty for every Topic.uids- The user IDs.message- The notification.- Returns:
- The result.
- Throws:
Exception- If the send fails or times out.
spoolFile
Gets the default spool file of a server:<spoolDirectory>/pnspool.xml, the spool directory being the setting when non-empty, elsepush-spoolunder the server's current directory.- Parameters:
settings- The settings.serverDir- The server's current directory.- Returns:
- The file.