moleculerjs / moleculer

:rocket: Progressive microservices framework for Node.js
https://moleculer.services/
MIT License
6.16k stars 586 forks source link

HotReload error on ES6 schemas #356

Closed xynon closed 6 years ago

xynon commented 6 years ago

Prerequisites

Please answer the following questions for yourself before submitting an issue.

Expected Behavior

If I use the HotReload of an service I expected that the service is stopping and then starting. Ok, the HotReload is implemented that before the service is starting it is loading/creating new and then it starting.

Current Behavior

The service don't starting again.

Failure Information

The HotReload watch the service file and if there are changes so the broker call the hotReloadService method. These are destroying and then loading the service in line 606.
That means Service.stopped is called in Broker.destroyService through Service._stop and then it will be calling Broker.loadService
From line 540 there are three expressions how to create the services.

if (this.ServiceFactory.isPrototypeOf(schema)) {
  // here would be used the new constructor
} else if (_.isFunction(schema)) {
 // here would be used the Broker.createService
} else if (schema) {
 // here would be used the Broker.createService too
}

If I understand that correctly - If I use ES6 schema the first expression resolves true then I don't call the Broker.createService, am I right?

So, there is my problem, if I don't use the Broker.createService then would a part of these method never call. This part what I mean is the expression if (this.started) { line 633 - I don't found the same functionallity in the constructor and imho that would be the wrong place anyway.
But the method after this.started === true will be never call Service._start And without these method the service called never the Service.started.

Steps to Reproduce

  1. Create a broker with enabled hot reload.
  2. Create an es6 service in an file.
  3. use Broker.loadService and load the service from 2.
  4. change the service to trigger the hot realod.
  5. see the service was stopped, then created new and then nothing... no started

Reproduce code snippet

I will be update that, if necessary.

Context

Failure Logs

Sorry it's my own log but I think it is acceptable:

2018-08-09T10:49:02.453Z - verbose: Successfully initialized micro service 'TestService'.
2018-08-09T10:49:02.453Z - info: Micro service 'TestService-1' is starting...
2018-08-09T10:49:02.472Z - info: Connecting to the transporter...
2018-08-09T10:49:02.562Z - info: AMQP is connected.
2018-08-09T10:49:02.574Z - info: AMQP channel is created.
2018-08-09T10:49:02.862Z - info: Node 'Test2Service-1' connected.
...
2018-08-09T10:49:03.481Z - verbose: Micro service 'TestService' started.
2018-08-09T10:49:03.537Z - info: Successfully started micro service 'TestService-1'.
2018-08-09T10:49:07.264Z - info: The test.v0.service.js is changed. (Type: rename)
2018-08-09T10:49:07.768Z - info: Hot reload 'TestService' service...
2018-08-09T10:49:07.806Z - verbose: Micro service 'TestService' stopped.
2018-08-09T10:49:07.810Z - info: Service 'TestService' is stopped.
2018-08-09T10:49:07.817Z - info: 'TestService' service is registered.
2018-08-09T10:49:07.817Z - verbose: Micro service 'TestService' created.
// should theoretically started again
xynon commented 6 years ago

An easy example: File structure:

main.js

const { ServiceBroker } = require('../moleculer');

const broker = new ServiceBroker({
  namespace: 'test',
  logger: console,
  hotReload: true,
});

broker.loadService('./service.js');
broker.start();

service.js

const { Service } = require('../moleculer');

class CustomService extends Service {

  constructor(broker) {
    super(broker);

    this.parseServiceSchema({
      name: 'custom',
      actions: {
        hello: this.hello,
      },
      created: this.serviceCreated,
      started: this.serviceStarted,
      stopped: this.serviceStopped,
    });
  }

  hello() {
    return 'Hello World';
  }

  serviceCreated() {
    console.log('Service created');
  }

  serviceStarted() {
    console.log('Service started');
  }

  serviceStopped() {
    console.log('Service stopped');
  }
}

module.exports = CustomService;

Log result:

/home/xynon/.nvm/versions/node/v10.8.0/bin/node -r trace -r clarify /home/xynon/workspace/moleculer-hot-reload-es6/main.js
[2018-08-13T09:49:42.400Z] INFO  xynon-32083/BROKER: Moleculer v0.13.1 is starting...
[2018-08-13T09:49:42.406Z] INFO  xynon-32083/BROKER: Node ID: xynon-32083
[2018-08-13T09:49:42.406Z] INFO  xynon-32083/BROKER: Namespace: test
[2018-08-13T09:49:42.408Z] INFO  xynon-32083/REGISTRY: Strategy: RoundRobinStrategy
[2018-08-13T09:49:42.411Z] INFO  xynon-32083/BROKER: Serializer: JSONSerializer
[2018-08-13T09:49:42.413Z] INFO  xynon-32083/BROKER: Registered 10 internal middleware(s).
Service created
Service started
[2018-08-13T09:49:42.438Z] INFO  xynon-32083/REGISTRY: '$node' service is registered.
[2018-08-13T09:49:42.439Z] INFO  xynon-32083/REGISTRY: 'custom' service is registered.
[2018-08-13T09:49:42.440Z] INFO  xynon-32083/BROKER: ServiceBroker with 2 service(s) is started successfully.

Change and save:

[2018-08-13T09:51:03.831Z] INFO  xynon-32083/BROKER: The service.js is changed. (Type: rename)
[2018-08-13T09:51:04.333Z] INFO xynon-32083/BROKER: Hot reload 'custom' service... /home/xynon/workspace/moleculer-hot-reload-es6/service.js
Service stopped
[2018-08-13T09:51:04.335Z] INFO  xynon-32083/BROKER: Service 'custom' is stopped.
Service created
xynon commented 6 years ago

Can you reproduce it or do you need some more information?

icebob commented 6 years ago

Sorry, I was on holiday, I have no time to try to reproduce. Maybe this week...

xynon commented 6 years ago

No problem, the issue it's just on the hot reload so it's easy to evade. If you start the broker normally - the Broker.start calls all start up routines correctly.

But it would be really nice if the hot reload feature work with es6 classes.

icebob commented 6 years ago

Thanks, I could reproduce. Now I'm fixing it...

icebob commented 6 years ago

Fixed.