Managing Service Dependencies and Inter-Service Calls in Moleculer
Learn how to use Moleculer's dependency system to control service startup order and use broker.call() for reliable inter-service communication.
22 Feb 2026, 05:39 UTC

Ensuring Service Availability with Dependencies
In a distributed microservices architecture, a service often cannot function until another service is ready to handle requests. In Moleculer, the primary way to manage this is through the dependencies array in the service schema. This ensures that the ServiceBroker resolves the startup order, preventing a service from entering the online state until all listed dependencies have successfully started.
The key takeaway is that dependencies control startup sequence, not runtime reliability. If a dependency crashes after the system is running, the dependencies array will not automatically restart it or provide a fallback; you must handle those scenarios using request timeouts and error catching during the actual call.
Implementing a Dependent Service Pattern
Consider a scenario where a comments service must validate that a post exists via a posts service before allowing a comment to be created. The comments service depends on the posts service to be online to avoid initial request failures.
// posts.service.js
module.exports = {
name: "posts",
actions: {
find(ctx) {
// Mock database lookup
const posts = { 1: { title: "Moleculer Guide" } };
return posts[ctx.params.id] || null;
}
}
};
// comments.service.js
module.exports = {
name: "comments",
// This ensures 'posts' is online before 'comments' starts
dependencies: ["posts"],
actions: {
async create(ctx) {
const { postId, text } = ctx.params;
// Use broker.call to invoke the dependency
// Format: 'serviceName.actionName'
const post = await this.broker.call("posts.find", { id: postId }, {
timeout: 3000 // Fail if posts service takes > 3s
});
if (!post) {
throw new Error("Post not found. Cannot create comment.");
}
return { success: true, message: "Comment added" };
}
}
};
How the Mechanism Works
- Lifecycle Ordering: When
broker.start()is called, the broker analyzes the dependency graph. It waits for thepostsservice to emit itsonlineevent before attempting to start thecommentsservice. - The Context (ctx): Every action receives a
ctxobject. Whilethis.broker.callis the standard way to invoke other services, thectxprovides the necessary metadata for the broker to route the request across the network (or locally) to the correct service instance. - Request Routing: The string
"posts.find"tells the broker to look for a service namedpostsand execute itsfindaction.
Operational Limits and Common Pitfalls
Startup Failures
If you declare dependencies: ["posts"] but the posts service is not registered with the broker (or fails to start), broker.start() will reject. This is a "fail-fast" mechanism. It prevents the application from entering a zombie state where it is running but incapable of performing its core functions.
The Async Trap
A common mistake is forgetting to await the this.broker.call() promise. Because broker.call is asynchronous, omitting await will cause the action to return a pending promise or undefined to the caller before the remote service has actually responded. This leads to race conditions and difficult-to-debug null pointer errors.
Runtime vs. Startup Dependencies
It is critical to distinguish between startup dependencies and runtime availability:
| Feature | Startup Dependency (dependencies) |
Runtime Call (broker.call) |
|---|---|---|
| Purpose | Ensures correct boot order. | Executes business logic. |
| Failure Result | Broker fails to start. | Action throws an error/timeout. |
| Scope | One-time check at launch. | Per-request execution. |
Verification and Testing
To verify this configuration, you can perform the following checks in a development environment (assuming Moleculer v2.x):
- Boot Order Check: Add a
started()lifecycle hook to both services that logs to the console. Confirm that thepostslog appears before thecommentslog. - Missing Dependency Test: Comment out the registration of the
postsservice and run the broker. The process should exit with an error indicating a missing dependency. - Timeout Validation: Temporarily add a
sleepfunction insideposts.findthat lasts 5 seconds. Callcomments.createand verify that it throws a timeout error after the specified 3 seconds.
Rollback Procedure
If the dependency chain causes circular dependency errors (Service A depends on B, and B depends on A), remove the dependencies array from one of the services. This allows both to start simultaneously, shifting the responsibility of availability handling entirely to the broker.call error handling logic.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.