# About Moleculer Services

The Service is a basic component in the Moleculer Ecosystem. Services may have Actions that other Services can invoke locally or over the network. Services can also define event Listeners that can react to events created in the Moleculer Cluster. Using the Moleculer Framework, Services written in different languages can work effectively with each other.

Moleculer can be integrated with the Spring Framework. In the Spring Environment, Moleculer Services and ServiceBroker are Spring Beans. This will allow Moleculer Services to access the other Spring Components (eg. DAO classes for access the backend).

The WEB API Gateway module enables the Moleculer Services to function as REST/HTML services generating HTML pages using server-side Template Engines. In addition, they can receive / send large files or send WebSocket packets to browsers.

# Actions

The actions are the callable/public methods of a Service. They are callable with "broker.call()" or "ctx.call()" methods.

Example

A Service schema of adding and subtracting two numbers (the example defines two Actions):




 




 






@Name("math")
public class MathService extends Service {

    Action add = ctx -> {
        return ctx.params.get("a", 0) + 
               ctx.params.get("b", 0);
    };
    
    Action sub = ctx -> {
        return ctx.params.get("a", 0) -
               ctx.params.get("b", 0);
    };
    
}

The "@Name" attribute isn't a mandatory property, if missing, MessageBroker will generate the Service name from the Class name. The algorithm used to create Services names is similar to when Spring registers Beans; the first letter will be lowercase, the rest will not change (for example, MathService registers as "mathService"). This rule also applies to Action names; you can specify the name with the "@Name" annotation; if missing, the Java field name will be the action name (eg. "add" Action registers as "add").

To register the MathService in a MessageBroker, use the "createService" method:


 


MessageBroker broker = MessageBroker.builder().build();
broker.createService(new MathService());
broker.start();

To call the Service, use the "call" method:



 




 



// in thread-blocking style:

Tree rsp = broker.call("math.add", "a", 5, "b", 3).waitFor();
System.out.println("Response: " + rsp.asInteger());

// ...or, in non-blocking style:

broker.call("math.sub", "a", 5, "b", 3).then(rsp -> {
    System.out.println("Response: " + rsp.asInteger());
});

From the caller perspective does not matter the physical location of the Service. The "math.add" and "math.sub" Actions can be on other machine, written in a different programming language.
Read more about Actions.

# Versioned Services


 





@Name("math")
@Version("2")
public class MathV2Service extends Service {

    // Modified "add" and "sub" Actions...    
}

To call the versioned Service, use the "v2." prefix:

broker.call("v2.math.add", "a", 5, "b", 3);

REST call

Via WEB API Gateway, make a request to GET /v2/math/add.

# Events

Services can monitor events. Events can come from local but also from remote nodes. The content of the event is a "JSON structure" (ctx.params) inside a Context object.

Example



 
 




public class PaymentService extends Service {

    @Subscribe("order.created")
    Listener orderCreated = ctx -> {
        logger.info("Received data:", ctx.params);
    };
}

Read more about event handling.

# Lifecycle handlers

There are some lifecycle service events, that will be triggered by the ServiceBroker.



 





 





public class TestService extends Service {

    public void started(ServiceBroker broker) throws Exception {
        super.started(broker);
        // Custom initialization functions
    }

    @Override
    public void stopped() {
        // Closing resources, stopping timers
    }
    
} 

These are called when ServiceBroker starts or stops the Services.
Read more about lifecycle of Services.

Other system-level events can be handled by event Listeners (eg. another Node joining the cluster or a change in the Service list).
Read more about internal events.

# Dependencies

If a Service depends on other Services, use the "@Dependencies" annotation to denote dependencies. The service waits for dependent services before calls the "started" lifecycle event handler.

 




@Dependencies({"logService", "backendService"})
public class RestService extends Service {
    // ...
}

The main difference between the "@Dependencies" annotation and Spring "@DependsOn" annotation is that "@Dependencies" monitors the entire Moleculer Cluster. In the example above, "logService" or "backendService" can be a remote Service. The Spring "@DependsOn" annotation only monitors the local ApplicationContext.

# Wait for services via ServiceBroker

To wait for services, you can also use the "waitForServices" method of ServiceBroker. It returns a Promise which will be resolved when all defined services are available & started.

Example

broker.waitForServices("posts", "users").then(rsp -> {
    // Called after the "posts" and "users" services are available
});

Handle timeout

broker.waitForServices(10 * 1000, "accounts").then(rsp -> {
    // Call it when the "accounts" service becomes available within 10 seconds
}).catchError(err -> {
    // Called if the wait time is more than 10 seconds
});

WARNING

Do not use the "waitForServices" method to block the Spring initialization process (for example, while creating Beans). ServiceBroker starts completely after Spring initialization is complete.