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.
Files. The engine owns one PushFileWatcher (design 7.3, ruling S-5): created at the first file to watch - the credentials file, or a key file the PushKeyFiles read - and closed at dispose(); none when nothing is watched.
- 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.Field Summary
FieldsModifier and TypeFieldDescriptionstatic final StringThe name of the engine's file watcher thread: "iizi-push-files".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.Gets the credentials: the credentials file ofPUSH-CREDENTIALS.mdand the users registered from Java, the first sources of the HTTP API's authentication and the group definitions of the database users.Gets the events hub the sessions' Push Notification listeners are fed from: a subscription stored or removed, a send target that failed (P4-04).intGets the number of sends in flight now.Gets the key files: the reader of every Push Notification key file of this server (PUSH-KEYFILES-DESIGN.mdsection 5), shared by the credentials and the application configurations and watched through this engine's watcher.intGets the ceiling the engine started with.Gets the registry of the Push Notification HTTP API's program users (PUSH-CREDENTIALS.mdsection 7, ruling R6; declared here by CC-PUSH-SERVER-INI decision 5, 2026-09-26): server code registers a user in memory with a password and the groups whose privileges it gets, and a program then authenticates with it over Basic authentication.Gets the region tree the router resolves residency against.Gets the resolver.Gets the push server ID (CC-DESIGN-PUSH-APPID-FILTER SV-1): a UUID made at the first engine start on the subscription database and kept there, the same for every server sharing it (SubscriptionStore.ensureServerId()).--- Accessors ---getSpool()Gets the spool.getState()Gets the current lifecycle state of the engine.getStore()Gets the store.getTransport(PushTransport kind) Gets a transport.getTransportState(PushTransport kind, String appId) Tells whether a transport can send for an application, and when not, why: the ONE check behindqueryAvailableTransportsand a client session'ssubscribe(CC-FIX-PUSH-V5 G-3, CC-V5-AUDIT-PUSH VP-D-3), so that a device is never subscribed under a configuration whose public half alone this server holds - a VAPID public key whose private key is not in this machine's secrets store, a Firebase project without its service account, a pair that does not match - which would store a row this server can never send to.getUsers()Gets the user directory.Gets the engine's file watcher: one per engine, created at the first file to watch - the credentials file or any key file - and closed bydispose()(design 7.3, S-5).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.send(String appId, String topic, long[] uids, IPushNotification message, DeliveryUrgency urgency) Sends a notification for an application and Topic to users by ID, or to every subscriber, with an urgency, the server's default policies otherwise and an unrestricted operator, and waits a bounded time: the HTTPpushof PUSH-WIRE-CONTRACT section 5.6.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, makes or reads the push server ID, loads the spool, loads and watches the credentials file, and starts the replay loop.
Field Details
WATCHER_THREAD_NAME
The name of the engine's file watcher thread: "iizi-push-files". One thread per engine, a daemon, watching the credentials file and every key file read.- See Also:
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, makes or reads the push server ID, loads the spool, loads and watches the credentials file, 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, and it is never revived.PushNotificationModuledisposes of the engine and unregisters it fromPushNotificationEngineProviderin the same step, so until a later server start registers a new engineIServer.getPushNotificationEngine()throwsUnsupportedOperationExceptionrather than returning this one; seeIPushNotificationService.- 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.
getPushUserRegistry
Description copied from interface:IPushNotificationEngineGets the registry of the Push Notification HTTP API's program users (PUSH-CREDENTIALS.mdsection 7, ruling R6; declared here by CC-PUSH-SERVER-INI decision 5, 2026-09-26): server code registers a user in memory with a password and the groups whose privileges it gets, and a program then authenticates with it over Basic authentication. Implemented by the engine's credentials, beside the users of the credentials file, which always wins over a registration.- Specified by:
getPushUserRegistryin interfaceIPushNotificationEngine- Returns:
- The registry; never
null.
getStore
getServerId
Gets the push server ID (CC-DESIGN-PUSH-APPID-FILTER SV-1): a UUID made at the first engine start on the subscription database and kept there, the same for every server sharing it (SubscriptionStore.ensureServerId()). Everydata.iizithis server writes carries it asserver(PUSH-WIRE-CONTRACT 6.2), the channel tells the device, and a receipt naming another ID is dropped (PushEvents.report(com.iizix.push.IPushReceipt,String,String)).- Returns:
- The ID, lower-case, 36 characters; null before
start()has read it.
getUsers
getConfigs
getCredentials
Gets the credentials: the credentials file ofPUSH-CREDENTIALS.mdand the users registered from Java, the first sources of the HTTP API's authentication and the group definitions of the database users. It is also theIPushUserRegistry, which application code reaches throughgetPushUserRegistry().- Returns:
- The credentials, never null.
getKeyFiles
Gets the key files: the reader of every Push Notification key file of this server (PUSH-KEYFILES-DESIGN.mdsection 5), shared by the credentials and the application configurations and watched through this engine's watcher.- Returns:
- The key files, never null.
getWatcher
getResolver
getSpool
getEvents
Gets the events hub the sessions' Push Notification listeners are fed from: a subscription stored or removed, a send target that failed (P4-04).- Returns:
- The events.
getTransport
Gets a transport.- Parameters:
kind- The kind.- Returns:
- The transport, or null when the engine has none of that kind.
getTransportState
Tells whether a transport can send for an application, and when not, why: the ONE check behindqueryAvailableTransportsand a client session'ssubscribe(CC-FIX-PUSH-V5 G-3, CC-V5-AUDIT-PUSH VP-D-3), so that a device is never subscribed under a configuration whose public half alone this server holds - a VAPID public key whose private key is not in this machine's secrets store, a Firebase project without its service account, a pair that does not match - which would store a row this server can never send to.- Parameters:
kind- The transport.appId- The application ID,*for the server's own configuration.- Returns:
- The state: not configured, with the reason, when the engine has no transport 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.
send
public PushResultImpl send(String appId, String topic, long[] uids, IPushNotification message, DeliveryUrgency urgency) throws Exception Sends a notification for an application and Topic to users by ID, or to every subscriber, with an urgency, the server's default policies otherwise and an unrestricted operator, and waits a bounded time: the HTTPpushof PUSH-WIRE-CONTRACT section 5.6.- Parameters:
appId- The application ID,*for every application.topic- The Topic, empty for every Topic.uids- The user IDs, null or empty for every subscriber (the broadcast).message- The notification.urgency- The urgency, null for the server default.- 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.