A Serbit is a component designed to process certain type of message, managed by ServiceContainer, that process messages by purpose which delivered from other services. A Service can be organized by combine multiple related serbits.
A Serbit uses a publish/subscribe model to process messages, which is optimized for asynchronously propagating messages between services.
A ServiceContainer received A ServiceContainer subscribes messages from various type of service and passes them to serbit, and publish messages which sent from serbit to the actual destination. A ServiceContainer also manages life cycle of serbit and resources using by serbit.
A Serbit is managed through life cycle that defines how it is instantiated, is initialized, process messages, taken out of service.
Each life cycle is expressed by the init, serve, and destroy APIs, and all serbit Implementations must implement these APIs for each language.
For example, in Java, Serbit is implemented as follows:
package io.pocat.platform;
public interface Serbit {
void init(SerbitConfig config) throws UnavailableException;
void serve(Delivery delivery) throws SerbitException;
void destroy() throws UnavailableException;
}
The Serbit must be instantiated at time chosen by the ServiceContainer. Instantiation order of Serbit is not guaranteed. ServiceContainer must contain exactly one instance for each serbit, that means, the implementation of serbit must guarantee concurrency.
If an error occured during instantiation, ServiceContainer must stop deploying service. A service should not be deployed if even only one serbit is failed to instantiate. The ServiceContainer must stop after proper error handling, such as logging.
After instantiate, ServiceContainer must initialize Serbits. ServiceContainer must create SerbitConfig instance per serbit and call init api with ServiceConfig as argument. The serbit can access initial parameter which is set by container by using SerbitConfig object. If serbit needs to use shared resources or context parameters of service, it can be done by using ServiceContext which is included SerbitConfig instance.
If all serbit is not initialized, ServiceContainer should not pass the message to the serbit.
By default, all serbits have the same priority 1, priority can be set in the service descriptor. Serbit initialization is processed in the order of priority and for the same priority, the order is not determined.
During initialization, Serbit init API is called with argument SerbitConfig object. SerbitConfig object contains information which is needed for initialization of serbit as following:
ServiceContext is an object to obtain information of service which the serbit belongs to. A ServiceContext instance is unique in service container, this means all serbit can access to the same instance of ServiceContext. A Serbit can access information of service like shared resources, context parameters, and so on through ServiceContext instance. You can set attributes in the ServiceContext in key-value format, and attributes set in one Serbit can be shared between Serbits included in the same ServiceContainer. ServiceContext has information as following:
If an error occured during instantiation,
ServiceContainer must stop initializing process and ServiceContainer must handle error properly.
The ServiceContainer can stop or retry initialization after proper error handling.
A service should not be deployed if even only one serbit is failed to initialize.
After initialization, Serbit can process message. It is the responsibility of ServiceContainer that send proper message to serbit by calling serve API.
See the "Message Delivery" chaptor for more details about the message.
Any errors that cannot be handled internally by the Serbit must be propagated to the ServiceContainer in a proper format like exception. ServiceContainer must handle error properly based on error code. If no error code provided, ServiceContainer must handle error with default error handling.
Serbit must be destroyed only when Service is terminated and cannot be destroyed individually. When a termination of service occurs, the ServiceContainer must stop all message subscription immediately and wait until remained messages are processed or stop message processing with error. When there are no more messages, ServiceContainer call destroy API of service in the reverse order of initialization
Message Delivery is the message structure delivered to the Serbit.
Message Delivery includes messages and management information.
The structure of Message Delivery are as follows:
Envelope contains the message management information as following:
A set of message headers
Message payload as byte array.
A Service is a set of one or more serbits.
A ServiceContainer must deploy only one Service.
The Service directory is structured as following:
Service Descriptor is a XML file to describe service architecture. Service Descriptor contains as following:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="service-descriptor" type="serviceDescriptorType"/>
<xs:complexType name="serviceDescriptorType">
<xs:sequence>
<xs:element name="name" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="serbits" type="serbitsType" minOccurs="1" maxOccurs="1"/>
<xs:element name="context-params" type="contextParamsType" minOccurs="0" maxOccurs="1"/>
<xs:element name="resource-refs" type="resourceRefsType" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="serbitsType">
<xs:sequence>
<xs:element name="serbit" type="serbitType" minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="serbitType">
<xs:sequence>
<xs:element name="serbit-name" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:choice minOccurs="1" maxOccurs="1">
<xs:element name="serbit-class" type="xs:string"/>
<xs:element name="serbit-script" type="xs:string"/>
</xs:choice>
<xs:element name="init-params" type="initParamsType" minOccurs="0" maxOccurs="1"/>
<xs:element name="description" type="xs:string" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
<xs:attribute name="order" type="xs:positiveInteger" default="1" use="optional" />
</xs:complexType>
<xs:complexType name="resourceRefsType">
<xs:sequence>
<xs:element name="ref" type="resourceRefType" minOccurs="1" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="resourceRefType">
<xs:attribute name="name" type="xs:string" use="required"/>
<xs:attribute name="type" type="xs:string" use="required"/>
<xs:attribute name="description" type="xs:string" use="optional"/>
</xs:complexType>
<xs:complexType name="initParamsType">
<xs:sequence>
<xs:element name="init-param" type="paramType" minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="contextParamsType">
<xs:sequence>
<xs:element name="context-param" type="paramType" minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="paramType">
<xs:attribute name="name" type="xs:string" use="required"/>
<xs:attribute name="default-value" type="xs:string" use="required"/>
<xs:attribute name="description" type="xs:string" use="optional"/>
</xs:complexType>
</xs:schema>
<service-descriptor>
<name>HelloService</name>
<serbits>
<serbit order="1">
<serbit-name>HelloSerbit</serbit-name>
<serbit-class>io.pocat.service.HelloSerbit</serbit-class>
<init-params>
<init-param name="locale" default-value="en" description="Greetings locale"/>
</init-params>
<description>HelloSerbit in English</description>
</serbit>
<serbit order="2">
<serbit-name>SalutSerbit</serbit-name>
<serbit-class>io.pocat.service.HelloSerbit</serbit-class>
<init-params>
<init-param name="locale" default-value="fr" description="Greetings locale"/>
</init-params>
<description>HelloSerbit in French</description>
</serbit>
</serbits>
<context-params>
<context-param name="default-locale" default-value="en" description="Default locale if locale does not set."/>
</context-params>
<resource-refs>
<ref name="greetingDatabase" type="javax,sql.DataSource" description="Greetings database"/>
</resource-refs>
</service-descriptor>