feathers
feathers copied to clipboard
Breaking a Feathers application into Microservices
There isn't still a proper documentation or tutorial on how to break feathers services into microservices, and there has been many request for this. My team is working with feathers and it is really difficult for us to work with all the services in one application. We will like to break them up. Or do we just split the services into multiple feathers apps?
Please how do we do this?
Yes even i need to understand how can i split into multiple microservices.
All Feathers apps are the same, whether built as individual microservices or as a bunch of services on a single machine. Each service is built on top of the application base. @eyeke04 you pretty much hit the nail on the head with your question. You split up your current "monolithic" Feathers app into two or more apps, each with its own service. You can use the Feathers client on the server to create the connection to your other services. Any services that your microservice references will have to be setup as Feathers client services that point to the remote destination. You can treat the Feathers Client as though it were a database adapter.
app.use('/local/service/alias', feathersClient.service('/remote/service'))
When i am posting a data to http://localhost:3000/service1 it is not reflecting but when i directly add to http://localhost:3001/service1 it is showing the data. Why?
//server.js
const feathers = require('feathers');
const bodyParser = require('body-parser');
const client = require('feathers/client');
const rest = require('feathers-rest');
const socketio = require('feathers-socketio');
const socketClient = require('feathers-socketio/client');
const io = require('socket.io-client');
const socket1 = io('http://localhost:3001');
const socket2 = io('http://localhost:3002');
const service1App = client().configure(socketClient(socket1));
const service2App = client().configure(socketClient(socket2));
const app = feathers()
// Enable REST services
.configure(rest())
// Enable REST services
.configure(socketio())
// Turn on JSON parser for REST services
.use(bodyParser.json())
// Turn on URL-encoded parser for REST services
.use(bodyParser.urlencoded({ extended: true }))
.use('/service1', service1App.service('service1'))
.use('/service2', service2App.service('service2'));
const service1 = service1App.service('service1')
service1.on('created', message => console.log('service1 Created a message', message));
const service2 = service2App.service('service2')
service2.on('created', message => console.log('service2 Created a message', message));
// Start the server.
const port = 3000;
app.listen(port, function () {
console.log(`Feathers server listening on port ${port}`);
});
///////////////////////// Service1 //////////////////// service1.js ///////////////////////// Service1 ////////////////////
const feathers = require('feathers');
const bodyParser = require('body-parser');
const rest = require('feathers-rest');
const socketio = require('feathers-socketio');
const memory = require('feathers-memory');
// Create a feathers instance.
const app = feathers()
// Enable REST services
.configure(rest())
// Enable REST services
.configure(socketio())
// Turn on JSON parser for REST services
.use(bodyParser.json())
// Turn on URL-encoded parser for REST services
.use(bodyParser.urlencoded({ extended: true }));
// Create an in-memory Feathers service with a default page size of 2 items
// and a maximum size of 4
app.use('/service1', memory({
paginate: {
default: 2,
max: 4
}
}));
// Create a dummy Message
app.service('service1').create({
text: 'Server message',
complete: false
}).then(function (message) {
console.log('Created message', message);
});
const service = app.service('service1');
service.on('created', message => console.log('Created a message', message));
// Start the server.
const port = 3001;
app.listen(port, function () {
console.log(`Feathers service1 listening on port ${port}`);
});
///////////////////////// Service2 //////////////////// service2.js ///////////////////////// Service2 ////////////////////
const feathers = require('feathers');
const bodyParser = require('body-parser');
const rest = require('feathers-rest');
const socketio = require('feathers-socketio');
const memory = require('feathers-memory');
// Create a feathers instance.
const app = feathers()
// Enable REST services
.configure(rest())
// Enable REST services
.configure(socketio())
// Turn on JSON parser for REST services
.use(bodyParser.json())
// Turn on URL-encoded parser for REST services
.use(bodyParser.urlencoded({ extended: true }));
// Create an in-memory Feathers service with a default page size of 2 items
// and a maximum size of 4
app.use('/service2', memory({
paginate: {
default: 2,
max: 4
}
}));
// Create a dummy Message
app.service('service2').create({
text: 'Server message',
complete: false
}).then(function (message) {
console.log('Created message', message);
});
const service = app.service('service2');
service.on('created', message => console.log('Created a message', message));
// Start the server.
const port = 3002;
app.listen(port, function () {
console.log(`Feathers service2 listening on port ${port}`);
});
///////////////////////// Service2 ////////////////////
@kethan
Try changing this line .use('/service1', service1App.service('service1'))
to something that you can better debug, like this:
.use('/service1', {
create (data) {
debugger;
return service1App.service('service1').create(data)
.then(response => {
console.log(response);
debugger;
})
.catch(error => {
console.log(error);
debugger;
})
}
})
Odd. I used a similar setup before, it looks like it should work. I'll see if I can reproduce the same problem.
@marshallswain I am getting this when i try to post to http://localhost:3000/service1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot POST /service1</pre>
</body>
@daffl I am afraid of this setup .. it this optimised way to do microservices or is there any better way you can suggest? How will socket connections scale? I will have each microservices running in cluster.
@kethan, what scares you about this setup?
@marshallswain i mean will socket.io service scale?
WebSockets are more efficient than regular HTTP 1 requests. Once connected, their overhead is much lower, per request. You're definitely going to need some sort of messaging bus, like feathers-sync. And you should be able to stick a load balancer in front of your services. I recommend at some point swapping the feathers-socketio
transport for the feathers-rest
one to compare and benchmark performance.
@marshallswain wow that sounds awesome!. How do I use feathers-sync in above example?..
And what about the status of the issue i posted?
You should be able to follow the docs in the README.md to get it setup. You'll need more machines, though. ;)
@daffl said he's going to test out the setup, above, so I'm going to defer to that so I can focus on some other work I'm doing.
Hi,
any updates on the issue I posted?
Not yet. I'm focusing on getting auth docs squared away, currently. I'll circle back to this afterwards. I have about 4 more guides to write. ;)
Also if you use the socketio solution how do you authenticated between the two. Any endpoints that require authentication will fail. Ideally need a way to allow requests from the microservice through.
I add my 2 cents on this with https://github.com/kalisio/feathers-distributed, it aims at deploying N feathers apps holding different services talking together, so that you can develop each one independently. It is different from https://github.com/feathersjs/feathers-sync which aims at deploying N feathers apps holding the same services as far as I understand. All of this raises a set of questions like:
- authentication management
- API gateway and load balancing
- remote hooks invokation
- ...
Hey @claustres do you want to add this to https://github.com/feathersjs/awesome-feathersjs? I'm planning on updating feathers-sync
and publish an article where I'll mention this one as well.
Done through https://github.com/feathersjs/awesome-feathersjs/pull/4. Depending on your schedule I might help on the article because I was thinking of writing something on this as well, I still miss some time to test a production use case...