Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Breaking a Feathers application into Microservices #536

Open
eyeke04 opened this issue Mar 23, 2017 · 18 comments
Open

Breaking a Feathers application into Microservices #536

eyeke04 opened this issue Mar 23, 2017 · 18 comments

Comments

@eyeke04
Copy link

eyeke04 commented Mar 23, 2017

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?

@kethan
Copy link

kethan commented Mar 23, 2017

Yes even i need to understand how can i split into multiple microservices.

@marshallswain
Copy link
Member

marshallswain commented Mar 23, 2017

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'))

@kethan
Copy link

kethan commented Mar 29, 2017

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 ////////////////////

@marshallswain
Copy link
Member

@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;
      })
  }
})

@daffl
Copy link
Member

daffl commented Mar 29, 2017

Odd. I used a similar setup before, it looks like it should work. I'll see if I can reproduce the same problem.

@kethan
Copy link

kethan commented Mar 29, 2017

@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>

@kethan
Copy link

kethan commented Mar 29, 2017

@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.

@marshallswain
Copy link
Member

@kethan, what scares you about this setup?

@kethan
Copy link

kethan commented Mar 29, 2017

@marshallswain i mean will socket.io service scale?

@marshallswain
Copy link
Member

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.

@kethan
Copy link

kethan commented Mar 29, 2017

@marshallswain wow that sounds awesome!. How do I use feathers-sync in above example?..

And what about the status of the issue i posted?

@marshallswain
Copy link
Member

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.

@kethan
Copy link

kethan commented Apr 7, 2017

Hi,

any updates on the issue I posted?

@marshallswain
Copy link
Member

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. ;)

@dottodot
Copy link

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.

@claustres
Copy link
Contributor

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
  • ...

@daffl
Copy link
Member

daffl commented Feb 6, 2018

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.

@claustres
Copy link
Contributor

Done through feathersjs/awesome-feathersjs#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...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants