PubSub functionality description

6.2 Pub/Sub Layer

In software architecture, publish–subscribe (PubSub or referred to as "Pub/Sub") is a messaging pattern where senders of messages, called publishers, do not program the messages to be sent directly to specific receivers, called subscribers, but instead categorize published messages into classes without knowledge of which subscribers if any, there may be. Similarly, subscribers express interest in one or more classes and only receive messages that are of interest, without knowledge of which publishers, if there are any.

Pub/Sub is a sibling of the message queue paradigm and is typically one part of a larger message-oriented middleware system. Most messaging systems support both the Pub/Sub and message queue models in their API; e.g. Java Message Service (JMS), which is especially useful to handle multiple retries in case a recipient application is offline due to connectivity issues, in a typical low-resource region.

This pattern provides greater network scalability and more dynamic network topology, with a resulting decreased flexibility to modify the publisher and the structure of the published data.

Any implementation of a Pub/Sub layer is subjective, it will contain required shapes for requests and specific endpoints provided by the application implementing the Pub/Sub functionality. The requirements below do not prescribe a specific implementation, rather they outline the required functionality that may be implemented in a number of common ways.

6.2.1 Adherence to Key Concepts

  1. The Publisher does not know about Subscribers (but the Room does know).

  2. Events of the same type can be generated by different producers.

  3. The Subscriber does not know about Producers.

    • There was a previous concern that the disconnect between producer and consumer would lead to legal issues (specifically, that authority or “blame” could not be allocated when one had to validate the origin of a particular event).

    • This has been addressed with “rooms”. For example, the room containing the “birth” event type is the responsibility of the Ministry of Health (MoH), and the MoH is responsible for ensuring that all “birth event” producers and all “birth event” subscribers are valid.

    • So, if you care about “birth events”, they may be sourced from lots of different hospitals/clinics/mobile apps, but their validation and distribution are now the sole responsibility of the MoH. (I.e., You can trust the MoH to ensure the provenance of a birth event.)

  4. The Room is responsible for the event lifecycle.

6.2.2 Facilitating Publish/Subscribe

  1. The Room publishes event types and sets up a GovStack service for accepting events of this type; in general, a single room might host multiple event types. Depending on the need, an implementation may also allocate each Room for a specific event type, if it helps separate subscribers. E.g. in India, "The Ministry Of Home Affairs" can be the "Owner" of a Room where events of type "emergency" are published by "citizens" or "entities" and entities such as "ambulance services", "Fire-fighting services", Hospitals, etc., can be Subscribers to this Room. In this scenario, an event of type "Fire emergency" can be published by any citizen enrolled in this Room. The Ministry can choose to have one "emergency" Room in each town and enroll Subscribers relevant to respective regions.

  2. Publishers and Subscribers discover available Rooms and event types.

  3. The Subscriber requests that events of certain types be delivered to them.

  4. The Subscriber specifies the desired delivery mode (push/pull). The Room and Subscriber conclude the delivery contract. Note that:

    • push delivery mode is when the Room sends events via webhook to the Subscriber’s API.

    • pull delivery mode (optional) means that the Room keeps a queue of events and the Subscriber can check that queue.

  5. At a minimum, this Building Block should provide for a push delivery mode. It may also provide a pull mode based on convenience.

  6. The Publisher and the Room have a data access contract to establish trust for accessing information.

    • This is akin to the standard trust contract in the Information Mediator, the consumer must have rights to access a certain API.

    • Publishers have to sign a contract with the Room owner’s consent to gain access to specific Rooms and events. In the contract, Publishers declare what type of message will be published in a given Room.

  7. The Publisher generates an event:

    • The Publisher makes a POST call to the Room service of a particular event type.

    • The Room stores the event and replies with the event id (e.g. Universally Unique IDentifier). Event id is generated by Room or is taken from the original event dataset if provided by the publisher.

    • The Room sends an immediate acknowledgement to the Publisher.

  8. The Room distributes an event as follows:

    • A reference to publisher and event id is added to the event dataset.

    • For each Subscriber:

      • (alt) If the mode is ‘push’, make a POST call to Subscriber GovStack service of the event type;

      • (alt) If the mode is ‘pull’, enqueue an event for request from the Subscriber;

        • There is a queue of events waiting to be processed per the Subscriber, such that the Subscriber might periodically check to see events waiting in their own queue, process those events, and clear the queue.

        • A pull mechanism is essential for resilience to network dropouts and traffic load balance at servers and for differentiating urgent/emergency events from normal events (this can be decided during implementation).

  9. (opt - if mode is PULL) The Subscriber pulls an event:

    • The Subscriber makes a GET call to the Room service of the particular event type.

  10. (opt) The Subscriber requests event details. Some event details may have more restricted regulations for handling and may be not included in event type. In this case, the Subscriber requests these details directly from the publisher by making a GET call to the referenced Publisher with event id as a parameter.

    • This call implies the existence of an associated contract between the Subscriber and the Publisher.

  11. The Information Mediator Building Block creates a log of all messages published and distributed.

  12. This necessitates three endpoints to be declared per event type Pub/Sub instance:

    • an endpoint URI to be registered by every Subscriber on a per-event type basis.

    • (optional) an endpoint URI on the Pub/Sub where all pull requests come from various Subscribers.

    • an endpoint in the Room to send messages for publication.

  13. An enrollment process of Subscribers and Publishers should capture these details.

  14. If an event payload is very large, then it is recommended to just publish the "event" and let Subscribers get full details directly from the Publishers as needed. It will simplify event payloads, reduce Turnaround time (TAT), storage, and bandwidth significantly.

6.2.3 Defining Message Types

  1. Pub/Sub requires global agreement on event/message “types” (e.g., “newPatient” or “paymentCreated”) and the Pub/Sub layer must provide a mechanism for registering event types.

  2. For each event type, a JSON schema for the required payload shape must be defined to facilitate the consumption of those events.

  3. An interface for registering and viewing event types must be provided.

6.2.4 Broadcasting a Message

An application must be able to make a POST request with a valid JSON payload as the body (see below) and specify the message type to a Room provided by the Pub/Sub layer service.

6.2.5 Maintaining and Displaying Message Logs

  1. All broadcast messages and deliveries/delivery statuses must be added to log.

  2. There must be a possibility to search and view status of messages, for example, a message with type X and from seven subscribers message had been successfully delivered to all seven.

6.2.6 Retrying Messages

  1. Published messages SHOULD be stored so that delivery may be retried if certain Subscribers are offline.

    • Subscribers should be able to configure their retry strategies, overriding the default exponential backoff on retriable errors. (Google Pub/Sub example)

  2. If an active subscription exists but a 502 response is received when forwarding a message to that service, the Pub/Sub layer SHOULD retry N times with a standard backoff. (An exponential backoff may be the default approach.)

    • The backoff and retry strategy SHOULD be configurable by an administrator with access to the Pub/Sub layer application.

  3. If a message cannot be delivered the Pub/Sub layer SHOULD drop that message.

6.2.7 Registering/Updating/Deleting a Subscription

  1. The Pub/Sub layer should provide an admin user interface to help create/manage subscriptions with the data below.

  2. The Pub/Sub layer should allow an administrator to view a list of active subscriptions.

  3. For registration via API, an application must be able to make a POST request to a service exposed by the Pub/Sub layer which defines which endpoints certain event types should be sent to.

  4. For services that provide an OpenAPI v3 webhooks specification, the Pub/Sub layer should be able to create necessary webhooks on those applications via API.

  5. See below for a JSON description of the active subscriptions for an application.

{ securityServer: nk888, member: "112 (Ministry of Public Engagement) hl7-2.5", application: 'Patient Portal', // WHO I AM… subscriptions: [ // AND WHAT I WANT TO BE NOTIFIED ABOUT… { type: "newPatient", service: '/openfn/inbox/uuid' }, { type: "newMedication", service: '/api/approvedMedsListing' }, ] }

6.2.8 Message Receipt/Delivery Logging and Audit Trail Generation

  1. All events received and delivered MUST have a unique ID.

  2. All events received by the Pub/Sub layer MUST be logged or added to a log sync and those log entries MUST contain event metadata including the sender, timestamp, and event type, but MAY not include the event payload.

  3. All event delivery attempts MUST be logged or added to a log sync.

  4. For every event message received, the Information Mediator sends back an acknowledgement with the ID of event to the respective Publisher.

6.2.9 Understanding Rooms

To understand Rooms, consider the following example: If the "birth" event type is the responsibility of the MoH, then the MoH is responsible for the Room containing the “birth” event type. Also, if MoH is running an instance of a security server on their infrastructure, they are also now running an instance of the Room software (for "birth", "sickness", and "visit" event types) behind that security server. There could be multiple Rooms under a single owner, and each Room might hold multiple event types. This gives the “owner” of an “event type” the authority to decide exactly who is allowed to publish events of that type and who is allowed to subscribe to events of that type.

https://lucid.app/lucidspark/ae9dba58-c15d-43b2-b8ef-9d15f6bd746c/edit - The above diagram shows push delivery mode.

Note how in the above diagram, “Ambulance-B” is an Information Mediator Building Block “member” that has subscribed its “Ambulance System B” REST service (/api/some-service) to “fire” events in the “State Emergency Room”.