Calling nestjs gRPC service on AWS ECS Fargate, Connection not established - nestjs

I have 2 nestjs microservices deployed to the AWS ECS(Fargate).
Service A exposes HTTP endpoints and works as gateway, and service B is using gRPC with nestjs. Service A calls service B gRPC API.
I’ve deployed both services on AWS ECS (Fargate) and using service discovery for service B. I’ve verified the service discovery name can be resolved with Cloud9 IDE.
Everything works end to end when I run them locally (hit service A’s endpoint and then service would call service B and get expected response). After deployment, I also verified that service B is reachable using postman gRPC request to directly call service B using public IP.
However, in Fargate, when service A tries to call service B, I keep getting Error 14 UNAVAILABLE Connection not established.
Below are how I bootstrap Service B and how I initiate Service B’s client in Service A
Bootstrap service B
async function bootstrap() {
const app: INestMicroservice = await NestFactory.createMicroservice(AppModule, {
transport: Transport.GRPC,
options: {
url: '0.0.0.0:50051',
package: protobufPackage,
protoPath: join('node_modules/services-proto/proto/serviceb.proto'),
},
});
app.useGlobalFilters(new HttpExceptionFilter());
app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true }));
await app.listen();
}
bootstrap();
Initiate service B client in service A
imports: [
ClientsModule.register([
{
name:SERVICE_B_NAME,
transport: Transport.GRPC,
options: {
url: process.env.SERVICE_B_URL,
package: SERVICE_B_PACKAGE_NAME,
protoPath: 'node_modules/services-proto/proto/serviceb.proto',
},
},
]),
],
Appreciate any help! Thanks!
I have tested locally and everything works from end to end. I could successfully hit service A’s HTTP endpoint and service successfully invoked service B’s gRPC API.
I’ve verified on AWS Cloud9 IDE that service discovery of service B are successfully resolved.
I’ve make sure inbound rule and outbound rule are set correctly for both security groups of service A and service B.
I’ve tested the service B’s gRPC is reachable with postman gRPC request.

Related

Service Discovery in Cloud Run

I have two micro services on Google Cloud Run which are meant to communicate via gRPC
Products Service
Customer Service.
Product Service is started like below:
....
let server = new grpc.Server();
server.addService(products_proto.Product.service, {...});
server.bindAsync("0.0.0.0:50051", grpc.ServerCredentials.createInsecure(), () => {
server.start();
console.log('Product Service Started');
});
...
How can Product Service locate Customer Service in production without explicitly specifying the port?
Or do I have to always ask my colleagues to tell me the port they exposed their micro-service on?
Wouldn't that be a very tedious process?
I want my product service to connect to my customer service using something like
....
new customer_proto.Customer("customer-service", grpc.credentials.createInsecure());
....
Instead of
....
new customer_proto.Customer("0.0.0.0:50052", grpc.credentials.createInsecure());
....
Can this be achieved?

How to get correct WSDL URL when hosting a WCF service behind an Azure Application Gateway?

We are in the process of migrating services from on-premise to Azure, and we are now hosting a legacy WCF service an Azure App Service. To make it backwards compatible with existing clients, it needs to be available through {domainNameHere}.com/services.
There are also other services that should be accessible through the same domain, for example {domainNameHere}.com/api. We have set up an Azure Application Gateway to route requests to different App Services based on the request paths, and have set {domainNameHere}.com to point to the Application Gateway IP.
This works well for all the services except for the WCF service. It is accessible in the browser at https://{domainNameHere}.com/services/exports.svc, but the WSDL URIs at that page shows the azurewebsites.net URIs instead of our custom domain. When clients attempt to access the service, they get the following error:
System.ServiceModel.EndpointNotFoundException:
'There was no endpoint listening at https://{domainNameHere}.com/services/export.svc
that could accept the message. This is often caused by an incorrect address or SOAP
action. See InnerException, if present, for more details.'
Inner Exception
WebException: The remote server returned an error: (404) Not Found.
We have tried to use useRequestHeadersForMetadataAddress in the WCF config to no avail.
Here is the WCF configuration, all in code. The endpoint URI is https://{domainNameHere}.com/services/exports.svc.
public static void Configure<T>(ServiceConfiguration config, Uri endpoint) where T : class
{
// Configure service behavior
config.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true, HttpsGetEnabled = true });
config.Description.Behaviors.Add(new ServiceDebugBehavior { IncludeExceptionDetailInFaults = true });
var serviceCredential = config.Description.Behaviors.Find<ServiceCredentials>();
if (serviceCredential == null)
{
serviceCredential = new ServiceCredentials();
config.Description.Behaviors.Add(serviceCredential);
}
serviceCredential.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
serviceCredential.UserNameAuthentication.CustomUserNamePasswordValidator = new CredentialsValidator();
config.AddServiceEndpoint(typeof(T), GetBinding(), endpoint);
}
I finally figured it out. The Application Gateway made requests to the WCF service using HTTP, but the WCF service only replied on HTTPS. As soon as I updated the Application Gateway to make requests using HTTPS it was working as expected.

React Node Microservice app works locally but not once deployed to AWS ECS

I'm trying to deploy an application to AWS ECS. The application's backend is a microservice and the client side is a react app with server-side rendering.
The backend is deployed in the private subnet in ECS with an internal load balancer. Same with the client side, deployed in the same private subnet but in a different ECS cluster( with separate ECS instances ). Also, the client side is connected to an internet-facing Application Load Balancer.
Following diagram depicts the AWS architecture I described
The issue
Whenever a GET or a POST or any other HTTP request made by the React App doesn't reach the backend. But all of these works fine when I run the app locally
When I SSH into the client side's ECS instance and do a GET or a POST call using CURL with the backend internal load balancer DNS name, it works perfectly and does the appropriate HTTP request to the backend. I also tried the same thing by SSH into the client side docker container and works without any issues.
Following is an example of the action that makes the backend call
export function getData() {
return {
type: "GET_DATA",
payload: new Promise((resolve, reject) => {
app.auth().onAuthStateChanged((id) => {
if(id) {
axios.get(process.env.BACKEND_HOST+`/service1/${id}`)
.then((response) => {
if(response.data == "") {
reject(false);
}
resolve(response.data)
}).catch((error) => { console.log(error) })
} else {
reject(false);
}
})
})
}
}
Following is the error output I get when the above call is made
OPTIONS http://internal-cc-backend-lb-238318069.us-east-1.elb.amazonaws.com/service1/data net::ERR_CONNECTION_TIMED_OUT
Error: Network Error
at e.exports (bundle.js:30)
at XMLHttpRequest.f.onerror (bundle.js:30)
OPTIONS http://internal-cc-backend-lb-238318069.us-east-1.elb.amazonaws.com/service1 net::ERR_CONNECTION_TIMED_OUT
Error: Network Error
at e.exports (bundle.js:30)
at XMLHttpRequest.f.onerror (bundle.js:30)
GET http://internal-cc-backend-lb-238318069.us-east-1.elb.amazonaws.com/service1/XfSOjVUFCcSoNEsFljOPfP11XyG2 net::ERR_CONNECTION_TIMED_OUT
Error: Network Error
at e.exports (bundle.js:30)
at XMLHttpRequest.f.onerror (bundle.js:30)
I'm passing the Internal Load balancer's DNS name as an environment variable. Tested with console.log to see if the code is getting the correct DNS name and it does. When run locally i pass the hostname/port of each service separately.
I would really appreciate any inputs and insights on this and if you guys need more information please let me know, I'll update this question.
Thanks in advance!

NodeJS Application unable to access from Zuul API Gateway

I created a Node.js (Using ExpressJS) microservice and registered it with Eureka Discovery Server using eureka-js-client.
I already have some Java based microservices registered with Eureka and using it through Zuul API Gateway.
When I try to invoke a specific endpoint on my Node.js micro-service via API Gateway, it throws an error:
Caused by: com.netflix.client.ClientException: Load balancer does not
have available server for client: tryout
Note: tryout is the name of my demo service application.
i had the same issue setting vipAddress same as the app name
vipAddress: your_app_name
in the eureka client config solved it.

Running GraphQL server on Google Cloud App Engine

In node.js to run the endpoint locally, I use the following snippet in my app.js
app.use('/graphql', (0, _expressGraphql2.default)(function (req) {
return {
schema: _schema2.default,
pretty: true,
context: _extends({ db: _models2.default }, (0, _isUser2.default)(req.headers['authorization'].split(' ')[1]))
};
}));
app.listen(8080, function () {
However, my app isn't receiving any response from the endpoint on trying to reach hostname:8080/graphql. This works on my local machine.
The title of your post indicates that your node.js app is deployed in Google App Engine. There is no need to worry about assigning an IP address to your instance in that environment. Instances are managed by the App Engine, and so is the routing of requests to your application.
To access the app, once deployed to the App Engine, one only needs to address it following the pattern: app_name.appspot.com. Alternatively, for a custom domain, you can follow the “Using Custom Domains and SSL” guide [1]. Sub-chapter “Adding SSL to your custom domain” of this document may help you with the setting up of SSL, if needed.
The app listens on port 8080 by default in the app engine. This is of no concern to an outside caller, who can only use the following the pattern: app_name.appspot.com to call the app. This situation is valid for the app engine environment.
[1] https://cloud.google.com/appengine/docs/flexible/nodejs/using-custom-domains-and-ssl

Resources