Skip to content

Commit 107992b

Browse files
committed
Add gRPC retries
but not working with Fabric because ALB sets metadata which gets interpreted as 'pushback' by grpc-js.
1 parent f1d7e0e commit 107992b

File tree

9 files changed

+79
-36
lines changed

9 files changed

+79
-36
lines changed

client.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import * as grpc from "@grpc/grpc-js";
2+
import * as fabric from "./protos/io/defang/v1/fabric_grpc_pb";
3+
import { Status } from "@grpc/grpc-js/build/src/constants";
4+
5+
function hasPort(url: string): boolean {
6+
return /:\d+$/.test(url);
7+
}
8+
9+
export function newClient(
10+
fabricDns: string,
11+
accessToken: string
12+
): fabric.FabricControllerClient {
13+
const serviceConfig: grpc.ServiceConfig = {
14+
loadBalancingConfig: [],
15+
methodConfig: [
16+
{
17+
name: [{ service: "io.defang.v1.FabricController" }],
18+
retryPolicy: {
19+
maxAttempts: 5,
20+
initialBackoff: "1s",
21+
maxBackoff: "10s",
22+
backoffMultiplier: 2,
23+
retryableStatusCodes: [Status.UNAVAILABLE, Status.INTERNAL],
24+
},
25+
},
26+
],
27+
};
28+
const noTenant = fabricDns.replace(/^.*@/, "");
29+
const withPort = hasPort(noTenant) ? noTenant : `${noTenant}:443`;
30+
return new fabric.FabricControllerClient(
31+
withPort,
32+
grpc.credentials.combineChannelCredentials(
33+
grpc.credentials.createSsl(),
34+
grpc.credentials.createFromMetadataGenerator((_, callback) => {
35+
const metadata = new grpc.Metadata();
36+
// TODO: automatically generate a new token once it expires
37+
metadata.set("authorization", "Bearer " + accessToken);
38+
callback(null, metadata);
39+
})
40+
),
41+
{ "grpc.service_config": JSON.stringify(serviceConfig) }
42+
);
43+
}

index.ts

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { dirname, join } from "path";
77
import { promises as stream } from "stream";
88
import assert = require("assert");
99

10+
import { newClient } from "./client";
1011
import * as fabric from "./protos/io/defang/v1/fabric_grpc_pb";
1112
import * as pb from "./protos/io/defang/v1/fabric_pb";
1213
import { createTarball, uploadTarball } from "./upload";
@@ -74,27 +75,11 @@ export function setAccessToken(token: string) {
7475
accessToken = token;
7576
}
7677

77-
function hasPort(url: string): boolean {
78-
return /:\d+$/.test(url);
79-
}
80-
8178
// Connect to our gRPC server
8279
async function connect(
8380
fabricDns: string
8481
): Promise<fabric.FabricControllerClient> {
85-
const withoutTenant = fabricDns.replace(/^.*@/, "");
86-
const client = new fabric.FabricControllerClient(
87-
hasPort(withoutTenant) ? withoutTenant : `${withoutTenant}:443`,
88-
grpc.credentials.combineChannelCredentials(
89-
grpc.credentials.createSsl(),
90-
grpc.credentials.createFromMetadataGenerator((_, callback) => {
91-
const metadata = new grpc.Metadata();
92-
// TODO: automatically generate a new token once it expires
93-
metadata.set("authorization", "Bearer " + getAccessToken(fabricDns));
94-
callback(null, metadata);
95-
})
96-
)
97-
);
82+
const client = newClient(fabricDns, getAccessToken(fabricDns));
9883
await new Promise<void>((resolve, reject) =>
9984
client.waitForReady(Date.now() + 5000, (err) =>
10085
err ? reject(err) : resolve()
@@ -301,7 +286,7 @@ async function upsert(
301286
if (secret.value === undefined) {
302287
return;
303288
}
304-
const sv = new pb.SecretValue();
289+
const sv = new pb.PutConfigRequest();
305290
sv.setProject(inputs.project);
306291
sv.setName(secret.source);
307292
sv.setValue(secret.value);
@@ -868,7 +853,7 @@ export class DefangService extends pulumi.dynamic.Resource {
868853
args.fabricDNS = defaultFabric;
869854
}
870855
if (!args.project) {
871-
args.project = pulumi.getProject()+"-"+pulumi.getStack();
856+
args.project = pulumi.getProject() + "-" + pulumi.getStack();
872857
}
873858
super(
874859
defangServiceProvider,

package-lock.json

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
},
88
"dependencies": {
99
"@balena/dockerignore": "^1.0.2",
10-
"@grpc/grpc-js": "^1.8.17",
11-
"google-protobuf": "^3.21.2",
10+
"@grpc/grpc-js": "^1.12.2",
11+
"google-protobuf": "^3.5.0",
1212
"node-fetch": "^3.3.1",
1313
"tar": "^6.1.15"
1414
},

tests/client.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import "mocha";
2+
import { newClient } from "../client";
3+
import * as pb from "../protos/io/defang/v1/fabric_pb";
4+
5+
describe("#newClient", () => {
6+
it("connect to fabric-prod1.defang.dev", function (done) {
7+
const client = newClient("fabric-prod1.defang.dev", "");
8+
9+
const trackRequest = new pb.TrackRequest();
10+
trackRequest.setEvent("Pulumi-Defang Test");
11+
client.track(trackRequest, (err) => (err ? done(err) : done()));
12+
});
13+
});

tests/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ const fromDir = new DefangService("test1", {
1111
healthcheck: {
1212
test: ["CMD", "wget", "--spider", "-q", "http://localhost/health"],
1313
retries: 1,
14+
timeout: 3,
15+
interval: 5,
1416
},
1517
waitForSteadyState: true,
1618
});

tests/package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
"typescript": "^5.1.3"
1212
},
1313
"dependencies": {
14-
"@defang-io/pulumi-defang": "^0.16.1",
14+
"@defang-io/pulumi-defang": "^0.17.2",
1515
"@pulumi/pulumi": "~3.117.0"
1616
},
1717
"scripts": {
1818
"test": "mocha --require ts-node/register *.test.ts",
19-
"posttest": "pulumi login file://. && PULUMI_CONFIG_PASSPHRASE= pulumi up -s test --yes ; pulumi destroy -s test --yes"
19+
"posttest": "pulumi login file://. && PULUMI_CONFIG_PASSPHRASE= pulumi up -s test --yes --refresh ; pulumi destroy -s test --yes"
2020
}
2121
}

tests/upload.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { dirname, resolve } from "path";
55
import * as upload from "../upload";
66
import * as tar from "tar";
77

8-
describe("createTarball", () => {
8+
describe("#createTarball", () => {
99
const expected = [
1010
"./",
1111
"./Dockerfile.test",

0 commit comments

Comments
 (0)