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

feat(boot): implement Service booter #1652

Merged
merged 4 commits into from
Aug 30, 2018
Merged

Conversation

bajtos
Copy link
Member

@bajtos bajtos commented Aug 28, 2018

Implement automatic discovery and registration of Service providers - see #1439 for the full context and #1649 for the first step on that journey.

This pull request has three parts/commits, the first two are preparations making the actual implementation easier to make and troubleshoot.

feat(testlab): expose "sandbox.path" property (4e86b08)

Allow TestSandbox consumers to access the path of the sandbox directory.

Clean up the code by moving "validateInst" check into "path" getter,
thus avoiding the need to explicitly call "validateInst" in every
public API method.

feat(boot): add debug logs for better troubleshooting (f88e776)

Make it easier to troubleshoot the situation when a booter is not
recognizing artifact files and/or classes exported by those files.

To make debug logs easy to read, absolute paths are converted to
project-relative paths in debug logs. This change required a refactoring
of Booter design, where "projectRoot" becomes a required constructor
argument.

While making these changes, I changed "options" to be a required
constructor argument too, and chaged both "options" and "projectRoot"

feat(boot): implement Service booter

The main change.

Checklist

  • npm test passes on your machine
  • New tests added or existing tests modified to cover all changes
  • Code conforms with the style guide
  • API Documentation in code was updated
  • Documentation in /docs/site was updated
  • Affected artifact templates in packages/cli were updated
  • Affected example projects in examples/* were updated

};

function isServiceProvider(cls: Constructor<{}>): cls is ServiceProviderClass {
return /Provider$/.test(cls.name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should check the existence of value().

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, I add that check to the existing name check.

(IMO, checking just for value is not enough, as there may be other classes/interfaces that contain value method too.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be documentation stating that the Booter is expecting Provider to be a part of the class name.

greet(whom: string = 'world') {
return Promise.resolve(`Hello ${whom}`);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we going to bind plain service class during boot? I don't see the logic.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not yet. The logic here is to ensure that the booter is picking only Providers and excludes regular classes, there is an integration test for that.

https://github.com/strongloop/loopback-next/blob/9098ad3ade0b226e90291c0f3365b290bd508a66/packages/boot/test/integration/service.booter.integration.ts#L23-L26

Suggestions are welcome on how to make this more obvious to people reading this code.

Maybe it's a sign that I should enhance ServiceMixin and the booter to handle both app.serviceProvider(GeocoderServiceProvider) and app.service(GreeterService) cases, even though app.service may not be used by any real LB4 app? IDK.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now, let's just add a comment to GreeterService saying it will be excluded from discovery as we only allow providers so far.

this.discovered = await discoverFiles(this.glob, this.projectRoot);

if (debug.enabled) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why have a check here? Doesn't debug only log if the debugger is enabled?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because JSON.stringify is expensive. The parameters will be calculated before invoking debug itself.

import {promisify} from 'util';
const glob = promisify(require('glob'));

const debug = debugFactory('loopback:boot:base-artifact-booter');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be loopback:boot:booter-utils?

};

function isServiceProvider(cls: Constructor<{}>): cls is ServiceProviderClass {
return /Provider$/.test(cls.name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be documentation stating that the Booter is expecting Provider to be a part of the class name.

Allow TestSandbox consumers to access the path of the sandbox directory.

Clean up the code by moving "validateInst" check into "path" getter,
thus avoiding the need to explicitly call "validateInst" in every
public API method.
@bajtos bajtos force-pushed the feat/service-booter branch from 9098ad3 to 10eb11b Compare August 30, 2018 08:38
bajtos added 3 commits August 30, 2018 10:39
Make it easier to troubleshoot the situation when a booter is not
recognizing artifact files and/or classes exported by those files.

To make debug logs easy to read, absolute paths are converted to
project-relative paths in debug logs. This change required a refactoring
of Booter design, where "projectRoot" becomes a required constructor
argument.

While making these changes, I changed "options" to be a required
constructor argument too, and chaged both "options" and "projectRoot"
to readonly properties.
 - address review comments
 - use ServiceBooter in example apps
 - update tutorial pages
 - update docs
@bajtos bajtos force-pushed the feat/service-booter branch from 10eb11b to cc0e108 Compare August 30, 2018 08:40
@bajtos
Copy link
Member Author

bajtos commented Aug 30, 2018

I have addressed your review comments and finished updates of example apps and docs - see 36a8eac.

The pull request is ready for the final review and landing.

@raymondfeng @virkt25 PTAL again.

@bajtos bajtos added this to the August Milestone milestone Aug 30, 2018

**IMPORTANT:** For a class to be recognized by `ServiceBooter` as a service
provider, its name must end with `Provider` suffix and its prototype must have a
`value()` method.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me, this is a sign that we should have something like #992 to make it possible to explicit.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense 👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for #992, it's certainly needed.

@@ -12,12 +12,14 @@ Let's start by creating the initial application by running the following
command:

```sh
lb4 app soap-calculator --enableRepository
lb4 app soap-calculator --enableRepository --enableServices
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, now we have enableRepository vs enableServices. The naming is inconsistent.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. Should we rename --enableRepository to --enableRepositories? I can do that in a follow-up pull request.

@raymondfeng raymondfeng merged commit 9cab3a9 into master Aug 30, 2018
@raymondfeng raymondfeng deleted the feat/service-booter branch August 30, 2018 17:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants