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

Microservices: Order of pattern fields #2428

Merged
merged 19 commits into from
Jun 28, 2019

Conversation

Geass1000
Copy link
Contributor

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

[ x ] Bugfix
[ x ] Feature
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Build related changes
[ ] CI related changes
[ ] Other... Please describe:

What is the current behavior?

When we send/emit request according to some object pattern, pattern doesn’t sort pattern’s fields . Pattern:

{ controller: `main`, service: `users`, use: `addUser` }

doesn’t equal:

{ service: `users`, controller: `main`, use: `addUser` }

Thus, if we try to catch a pattern using MessagePattern or EventPattern, nest will not call a required handler.

What is the new behavior?

I added simple middle-logic, that parses a patterns, sorts fields and creates a new pattern (route).

Does this PR introduce a breaking change?

[ ] Yes
[ x ] No

Other information

@coveralls
Copy link

coveralls commented Jun 21, 2019

Pull Request Test Coverage Report for Build 3326

  • 26 of 26 (100.0%) changed or added relevant lines in 4 files are covered.
  • 4 unchanged lines in 2 files lost coverage.
  • Overall coverage increased (+0.007%) to 94.961%

Files with Coverage Reduction New Missed Lines %
packages/microservices/server/server.ts 1 93.1%
packages/microservices/client/client-grpc.ts 3 94.17%
Totals Coverage Status
Change from base Build 3263: 0.007%
Covered Lines: 3486
Relevant Lines: 3671

💛 - Coveralls

@@ -18,11 +18,14 @@ import {
WritePacket,
} from '../interfaces';

import * as Utils from '../utils';
Copy link
Member

Choose a reason for hiding this comment

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

Why did you use import * as instead of importing a particular class?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't see any reason why I can't use it :) It provides an isolated scope (utils/interfaces/enums etc) and allows me to make import section more simple.

export abstract class ClientProxy {
public abstract connect(): Promise<any>;
public abstract close(): any;

protected routingMap = new Map<string, Function>();
protected readonly msvcUtil = Utils.MsvcUtil;
Copy link
Member

Choose a reason for hiding this comment

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

The variable name isn't very descriptive (+using msvc seems to be redundant here)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In my opinion, if other programmer sees this variable it will understand what is it. What name do you suggest?

@@ -18,27 +18,31 @@ import {
} from '../interfaces';
import { NO_EVENT_HANDLER } from './../constants';

import * as Utils from '../utils';
Copy link
Member

Choose a reason for hiding this comment

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

Same as above

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't see any reason why I can't use it :) It provides an isolated scope (utils/interfaces/enums etc) and allows me to make import section more simple.

export abstract class Server {
protected readonly messageHandlers = new Map<string, MessageHandler>();
protected readonly logger = new Logger(Server.name);
protected readonly msvcUtil = Utils.MsvcUtil;
Copy link
Member

Choose a reason for hiding this comment

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

Same as above

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In my opinion, if other programmer sees this variable it will understand what is it. What name do you suggest?

* @returns string
*/
private getRouteFromPattern(pattern: string): string {
let validPattern: any;
Copy link
Member

Choose a reason for hiding this comment

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

any -> Record<string, unknown> | string

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed.

let validPattern: any;

try {
// Gets the pattern in JSON format
Copy link
Member

Choose a reason for hiding this comment

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

This comment seems to be needless

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When I write code, I adhere to PPP (Pseudocode Programming Process). If you want, I will remove this comment.

validPattern = pattern;
}

// Transform the Pattern to Route
Copy link
Member

Choose a reason for hiding this comment

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

This comment seems to be needless

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When I write code, I adhere to PPP (Pseudocode Programming Process). If you want, I will remove this comment.

@@ -0,0 +1,39 @@
import { isString, isObject } from '@nestjs/common/utils/shared.utils';

export class MsvcUtil {
Copy link
Member

Choose a reason for hiding this comment

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

The filename + class name aren't very descriptive (+using msvc prefix seems to be redundant here)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What name do you suggest?

* @param {any} pattern - client pattern
* @returns string
*/
public static transformPatternToRoute(pattern: any): string {
Copy link
Member

@kamilmysliwiec kamilmysliwiec Jun 23, 2019

Choose a reason for hiding this comment

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

Why static? Why pattern: any?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I use classes for utils and static method allows me to use utils as singleton. Changed.

* @returns string
*/
public static transformPatternToRoute(pattern: any): string {
// Returns the pattern according to the 1st
Copy link
Member

Choose a reason for hiding this comment

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

This comment seems to be redundant (it's easy to infer from the context)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When I write code, I adhere to PPP (Pseudocode Programming Process). If you want, I will remove this comment.

return pattern;
}

// Throws the error if the pattern has an incorrect type
Copy link
Member

Choose a reason for hiding this comment

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

This comment seems to be redundant (it's easy to infer from the context)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When I write code, I adhere to PPP (Pseudocode Programming Process). If you want, I will remove this comment.

const sortedPatternParams = sortedKeys.map((key) =>
`${key}:${MsvcUtil.transformPatternToRoute(pattern[key])}`);

// Creates and returns the Route
Copy link
Member

Choose a reason for hiding this comment

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

This comment seems to be redundant (it's easy to infer from the context)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When I write code, I adhere to PPP (Pseudocode Programming Process). If you want, I will remove this comment.

@kamilmysliwiec
Copy link
Member

Great idea! Thanks for contribution :)

I left a few comments, could you look at them?

@kamilmysliwiec
Copy link
Member

I have nothing against your coding style, just want to ensure that newly added code is consistent with the project. I fixed gRPC issues (broken integration tests) + adjusted code style a little bit.

Thanks for your contribution! I'll release it soon

@kamilmysliwiec kamilmysliwiec merged commit 52caa02 into nestjs:master Jun 28, 2019
@JonathanMeyer2600
Copy link

Hello @kamilmysliwiec,

we have around 15 microservices in production. Upgrading to version > 6.4.0 changes the command name because of this feature. Before this the command name was {"cmd":"someCommand"}, now it is {cmd:someCommand}. This is making communication between services < 6.4.0 and >= 6.4.0 incompatible. We can't and don't want to update all services at once but one by one. This change is making it impossible. Any idea? Can we introduce the quotes again?

Thanks in advance,
Jonathan

@kamilmysliwiec
Copy link
Member

Hi @JonathanMeyer2600,
Apologize for the breaking change! The issue has been already fixed in the 6.5.2 release. Could you let me know if it works for you now?

@JonathanMeyer2600
Copy link

Hi @kamilmysliwiec
it's working! Thanks for the quick fix!

@Geass1000
Copy link
Contributor Author

Geass1000 commented Jul 10, 2019

Hello @kamilmysliwiec

When I was writing this code, I didn’t think about messages from other sources. I didn’t use JSON.stringify to encode the message and it made pattern (route) a bit smaller. But now code does the same thing as JSON.stringify and I see no reason not to use it. If you want, you can use something like that:

  const sortedPattern  = {};
  sortedKeys.map(key => {
    sortedPattern[key] = transformPatternToRoute(pattern[key]);
  });

  return JSON.stringify(sortedPattern);

I apologize about any inconvenience. :(

@kamilmysliwiec
Copy link
Member

No worries @Geass1000! :) I'll look at this soon, just wanted to fix the issue as quick as possible

@lock
Copy link

lock bot commented Oct 8, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Oct 8, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants