How to create a microservice
Microservices in
Microservices can also communicate in all directions, a consequence of the way in which messaging is used. They can also be factories to create instances of services that communicate exclusively with an owner.
Therefore, a microservice always consists of at least one target so that it can communicate.
In order for other parts of code to find the microservice, a microservice registers with a microservice registry.
Multiple registries can exist that automatically synchronize their datasets.
This ensures that this important part of
Microservice registries use broadcasts to ensure that each new node is informed about the existing registries. A local plugin collects this information and provides services related to the registration and deregistration of local microservices.
Therefore, it is very easy to write a microservice. It is sufficient to create a target, which, after registration at the target registry of a namespace, also registers at the microservice registry. Before the target is terminated, the microservice is deregistered by another call.
class CMyMicroserviceTarget extends CTarget implementsIService { private static final IId MICROSERVICE_ID = CIdFactory.fromObject("MyLovelyMicroservice"); // A random instance id private static final IId INSTANCE_ID = CIdFactory.randomOfType(EIdType.UUID); private final IDependenciesmDependencies ; CMyMicroserviceTarget(@NotNull finalIDependencies aDependencies) { mDependencies = aDependencies; addMessageHandler(CRecordStartTarget.ID, this::asyncStartTarget); addMessageHandler(CRecordDismiss.ID ,this::asyncDismiss ); } @Override public voidactivate (@NotNull final IServiceRegistry aServiceRegistry) throws Exception { final IId namespaceId = CIdFactory.random("MyMicroservice"); final INamespace ns =mDependencies.getNamespaceFactory() .createAndRegisterNamespace(namespaceId, "My Microservice Namespace"); ns.getTargetRegistry() .registerTarget(this); } @Override public voiddeactivate (@NotNull final IServiceRegistry aServiceRegistry) throws Exception {deregisterMicroservice() ; deregisterTarget(); } private booleanasyncStartTarget (@NotNull final CEnvelope aEnvelope, @NotNull final CRecord aRecord) throws CException { if (aEnvelope.isAnswer()) { return false; } else { registerMicroservice(); aEnvelope.setResultSuccess(); return true; } } private boolean asyncDismiss(@NotNull final CEnvelope aEnvelope, @NotNull final CRecord aRecord) throws CException { if (aEnvelope.isAnswer()) { return false; } else { deregisterMicroservice(); deregisterTarget(); aEnvelope.setResultSuccess(); return true; } } private voidregisterMicroservice() throws CException { // A list of records that belong to my API final List<CDescriptionOfRecord> api = new ArrayList<>(); api.add(new CDescriptionOfRecord(CRecordDismiss.ID, "Dismiss this service"));mDependencies.getHelperForLocalMicroServices() .registerMicroService(MICROSERVICE_ID, "My lovely microservice", api, INSTANCE_ID, getAddress()); } private voidderegisterMicroservice() throws CException {mDependencies.getHelperForLocalMicroServices() .deregisterMicroService(MICROSERVICE_ID, INSTANCE_ID); } }
The microservice class implements the interface
activate()
and deactivate()
methods.
The two methods are called by the package initializer.
See also Package Initialization.
In the
The
We have two dependencies: The namespace factory for creating namespaces (present in the kernel) and the microservice
helper (in the plugin NY_MicroservicePlugIn) for registering and unregistering the microservice.
The
IDependencies
interface.
interfaceDependencies { @NotNull INamespaceFactory getNamespaceFactory(); @NotNull IHelperForLocalMicroServices getHelperForLocalMicroServices(); }
Our target is started by a package initializer as usual, see Package Initialization.
public class CPackageExampleMicroservice implements IServiceStarter, IDependencies { private IService mService = null; private INamespaceFactory mNamespaceFactory; private IHelperForLocalMicroServices mHelperForLocalMicroServices; @Override public void getDependencies(@NotNull final IServiceDependencyList aDependencyList) { aDependencyList.add(INamespaceFactory.class); aDependencyList.add(IHelperForLocalMicroServices.class); } @Override public void start(@NotNull final IServiceRegistry aServiceRegistry) throws Exception { if (mService == null) { mNamespaceFactory = aServiceRegistry.getServiceOrThrow(INamespaceFactory.class); mHelperForLocalMicroServices = aServiceRegistry.getServiceOrThrow(IHelperForLocalMicroServices.class); mService = new CMyMicroserviceTarget(this); mService.activate(aServiceRegistry); } } @Override public void stop(@NotNull final IServiceRegistry aServiceRegistry) throws Exception { if (mService != null) { mService.deactivate(aServiceRegistry); mService = null; } } @Override public @NotNull INamespaceFactory getNamespaceFactory() { return mNamespaceFactory; } @Override public @NotNull IHelperForLocalMicroServices getHelperForLocalMicroServices() { return mHelperForLocalMicroServices; } }
Of course, you can also register a microservice with the microservice registry via message. It is important to note that when loading our plugin (when the node is booted) the microservice registry is not yet known. Microservice registries are announced to the new node via broadcast message. The broadcast probably arrives after our plugin has been loaded. You can of course register on the broadcast as an observer, which means that you receive the message directly with registration of the microservice registry. But the way shown is the easiest.