Skip to content

Commit b01aa2e

Browse files
committed
Merge branch 'upload/s3' of https://github.com/metatypedev/metatype into MET-432--Uploading--files-
2 parents ec70f26 + 85958d7 commit b01aa2e

File tree

4 files changed

+122
-105
lines changed

4 files changed

+122
-105
lines changed

typegate/deno.lock

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

typegate/src/typegate/artifacts/shared.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ async function initRemoteUploadUrlStore(
4343
return { redisClient };
4444
}
4545

46+
async function deinitRemoteUploadUrlStore(urlStore: RemoteUploadUrlStore) {
47+
await urlStore.redisClient.quit();
48+
}
49+
4650
function serializeToRedisValue<T>(value: T): string {
4751
return JSON.stringify(value);
4852
}
@@ -248,8 +252,8 @@ export class SharedArtifactStore extends ArtifactStore {
248252
);
249253
}
250254

251-
override close(): Promise<void> {
255+
override async close(): Promise<void> {
252256
this.#s3.destroy();
253-
return Promise.resolve(void null);
257+
await deinitRemoteUploadUrlStore(this.#uploadUrls);
254258
}
255259
}

typegate/tests/runtimes/wasmedge/wasmedge_sync_test.ts

Lines changed: 54 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -65,26 +65,26 @@ Meta.test(
6565
const port = metaTest.port;
6666
const gate = `http://localhost:${port}`;
6767

68-
await metaTest.should("work after deploying artifact to S3", async () => {
69-
const s3 = new S3Client(syncConfig.s3);
70-
assertEquals((await listObjects(s3, syncConfig.s3Bucket))?.length, 0);
71-
72-
const { serialized, typegate: gateResponseAdd } = await tgDeploy(tg, {
73-
baseUrl: gate,
74-
auth,
75-
artifactsConfig: {
76-
prismaMigration: {
77-
globalAction: {
78-
create: true,
79-
reset: false,
80-
},
81-
migrationDir: "prisma-migrations",
68+
const { serialized, typegate: gateResponseAdd } = await tgDeploy(tg, {
69+
baseUrl: gate,
70+
auth,
71+
artifactsConfig: {
72+
prismaMigration: {
73+
globalAction: {
74+
create: true,
75+
reset: false,
8276
},
83-
dir: cwd,
77+
migrationDir: "prisma-migrations",
8478
},
85-
typegraphPath: path.join(cwd, "wasmedge.ts"),
86-
secrets: {},
87-
});
79+
dir: cwd,
80+
},
81+
typegraphPath: path.join(cwd, "wasmedge.ts"),
82+
secrets: {},
83+
});
84+
85+
await metaTest.should("work after deploying artifact to S3", async () => {
86+
const s3 = new S3Client(syncConfig.s3);
87+
assertEquals((await listObjects(s3, syncConfig.s3Bucket))?.length, 2);
8888

8989
assertExists(serialized, "serialized has a value");
9090
assertEquals(gateResponseAdd, {
@@ -109,6 +109,41 @@ Meta.test(
109109
})
110110
.on(engine);
111111

112+
await engine.terminate();
113+
s3.destroy();
114+
});
115+
116+
await metaTest.should("work with multiple typegate instances", async () => {
117+
const s3 = new S3Client(syncConfig.s3);
118+
119+
// typegraphs are pushed to s3 whenever pushed to a typegate
120+
assertEquals((await listObjects(s3, syncConfig.s3Bucket))?.length, 3);
121+
122+
const engine = await metaTest.engineFromDeployed(serialized);
123+
124+
await gql`
125+
query {
126+
test_wasi_ts(a: 11, b: 12)
127+
}
128+
`
129+
.expectData({
130+
test_wasi_ts: 23,
131+
})
132+
.on(engine);
133+
134+
// second engine on the other typegate instance
135+
const engine2 = await metaTest.engineFromDeployed(serialized);
136+
137+
await gql`
138+
query {
139+
test_wasi_ts(a: 15, b: 2)
140+
}
141+
`
142+
.expectData({
143+
test_wasi_ts: 17,
144+
})
145+
.on(engine2);
146+
112147
const { typegate: gateResponseRem } = await tgRemove(tg, {
113148
baseUrl: gate,
114149
auth,
@@ -117,63 +152,8 @@ Meta.test(
117152
assertEquals(gateResponseRem, { data: { removeTypegraphs: true } });
118153

119154
await engine.terminate();
155+
await engine2.terminate();
120156
s3.destroy();
121157
});
122158
},
123159
);
124-
125-
// Meta.test(
126-
// {
127-
// name: "WasmEdge Runtime typescript SDK: Multiple typegate instances",
128-
// syncConfig,
129-
// async setup() {
130-
// await cleanUp();
131-
// },
132-
// async teardown() {
133-
// await cleanUp();
134-
// },
135-
// port: true,
136-
// multipleTypegates: 3,
137-
// },
138-
// async (metaTest) => {
139-
// const port = metaTest.port;
140-
// const gate = `http://localhost:${port}`;
141-
// await metaTest.should("work with multiple typegate instances", async () => {
142-
// const s3 = new S3Client(syncConfig.s3);
143-
// assertEquals((await listObjects(s3, syncConfig.s3Bucket))?.length, 0);
144-
145-
// const { serialized, typegate: _gateResponseAdd } = await tgDeploy(tg, {
146-
// baseUrl: gate,
147-
// auth,
148-
// artifactsConfig: {
149-
// prismaMigration: {
150-
// globalAction: {
151-
// create: true,
152-
// reset: false,
153-
// },
154-
// migrationDir: "prisma-migrations",
155-
// },
156-
// dir: cwd,
157-
// },
158-
// typegraphPath: path.join(cwd, "wasmedge.ts"),
159-
// secrets: {},
160-
// });
161-
162-
// assertEquals((await listObjects(s3, syncConfig.s3Bucket))?.length, 1);
163-
164-
// const engine = await metaTest.engineFromDeployed(serialized);
165-
166-
// await gql`
167-
// query {
168-
// test_wasi_ts(a: 11, b: 2)
169-
// }
170-
// `
171-
// .expectData({
172-
// test_wasi_ts: 13,
173-
// })
174-
// .on(engine);
175-
// await engine.terminate();
176-
// s3.destroy();
177-
// });
178-
// },
179-
// );

typegate/tests/utils/test.ts

Lines changed: 54 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,33 @@ export enum SDKLangugage {
3333
TypeScript = "deno",
3434
}
3535

36+
// with a round-robin load balancer emulation
37+
class TypegateManager {
38+
private index = 0;
39+
40+
constructor(private typegates: Typegate[]) {}
41+
42+
get replicas() {
43+
return this.typegates.length;
44+
}
45+
46+
next() {
47+
const typegate = this.typegates[this.index];
48+
this.index = (this.index + 1) % this.typegates.length;
49+
return typegate;
50+
}
51+
52+
async terminate() {
53+
await Promise.all(this.typegates.map((tg) => tg.deinit()));
54+
}
55+
}
56+
3657
interface ServeResult {
3758
port: number;
3859
cleanup: () => Promise<void>;
3960
}
4061

41-
function serve(typegate: Typegate): Promise<ServeResult> {
62+
function serve(typegates: TypegateManager): Promise<ServeResult> {
4263
return new Promise((resolve) => {
4364
const server = Deno.serve({
4465
port: 0,
@@ -51,7 +72,7 @@ function serve(typegate: Typegate): Promise<ServeResult> {
5172
});
5273
},
5374
}, (req) => {
54-
return typegate.handle(req, {
75+
return typegates.next().handle(req, {
5576
remoteAddr: { hostname: "localhost" },
5677
} as Deno.ServeHandlerInfo);
5778
});
@@ -72,13 +93,13 @@ export class MetaTest {
7293

7394
static async init(
7495
t: Deno.TestContext,
75-
typegates: Typegate[],
96+
typegates: TypegateManager,
7697
introspection: boolean,
7798
port = false,
7899
): Promise<MetaTest> {
79100
const mt = new MetaTest(t, typegates, introspection);
80101
if (port) {
81-
const { port: p, cleanup } = await serve(typegates[0]);
102+
const { port: p, cleanup } = await serve(typegates);
82103
mt.port = p;
83104
mt.addCleanup(cleanup);
84105
}
@@ -88,20 +109,16 @@ export class MetaTest {
88109

89110
private constructor(
90111
public t: Deno.TestContext,
91-
public typegates: Typegate[],
112+
public typegates: TypegateManager,
92113
private introspection: boolean,
93114
) {}
94115

95116
addCleanup(fn: MetaTestCleanupFn) {
96117
this.cleanups.push(fn);
97118
}
98119

99-
get typegate(): Typegate {
100-
return this.typegates[this.currentTypegateIndex];
101-
}
102-
103120
getTypegraphEngine(name: string): QueryEngine | undefined {
104-
return this.typegate.register.get(name);
121+
return this.typegates.next().register.get(name);
105122
}
106123

107124
async serialize(path: string, opts: ParseOptions = {}): Promise<string> {
@@ -140,7 +157,7 @@ export class MetaTest {
140157
}
141158

142159
async undeploy(tgName: string) {
143-
await this.typegate.register.remove(tgName);
160+
await this.typegates.next().register.remove(tgName);
144161
}
145162

146163
async engine(path: string, opts: ParseOptions = {}): Promise<QueryEngine> {
@@ -161,7 +178,7 @@ export class MetaTest {
161178
}
162179
}
163180

164-
const { engine, response } = await this.typegate.pushTypegraph(
181+
const { engine, response } = await this.typegates.next().pushTypegraph(
165182
tgJson,
166183
secrets,
167184
this.introspection,
@@ -171,15 +188,12 @@ export class MetaTest {
171188
throw response.failure!;
172189
}
173190

174-
this.currentTypegateIndex += 1;
175-
this.currentTypegateIndex %= this.typegates.length;
176-
177191
return engine;
178192
}
179193

180194
async engineFromDeployed(tgString: string): Promise<QueryEngine> {
181195
const tg = await TypeGraph.parseJson(tgString);
182-
const { engine, response } = await this.typegate.pushTypegraph(
196+
const { engine, response } = await this.typegates.next().pushTypegraph(
183197
tg,
184198
{},
185199
this.introspection,
@@ -211,20 +225,21 @@ export class MetaTest {
211225
}
212226

213227
async unregister(engine: QueryEngine) {
228+
const typegate = this.typegates.next();
214229
await Promise.all(
215-
this.typegate.register
230+
typegate.register
216231
.list()
217232
.filter((e) => e == engine)
218233
.map((e) => {
219-
this.typegate.register.remove(e.name);
234+
typegate.register.remove(e.name);
220235
return e.terminate();
221236
}),
222237
);
223238
}
224239

225240
async terminate() {
226241
await Promise.all(this.cleanups.map((c) => c()));
227-
await Promise.all(this.typegates.map((tg) => tg.deinit()));
242+
await this.typegates.terminate();
228243
}
229244

230245
async should(
@@ -294,7 +309,7 @@ interface TestConfig {
294309
// port on which the typegate instance will be exposed on expose the typegate instance
295310
port?: boolean;
296311
// number of typegate instances to create
297-
multipleTypegates?: number;
312+
replicas?: number;
298313
// create a temporary clean git repo for the tests
299314
gitRepo?: TempGitRepo;
300315
syncConfig?: SyncConfig;
@@ -321,26 +336,36 @@ export const test = ((o, fn): void => {
321336
if (opts.setup != null) {
322337
await opts.setup();
323338
}
324-
const typegates: Typegate[] = [];
325-
const typegate = await Typegate.init(opts.syncConfig ?? null);
326-
typegates.push(typegate);
327-
if (opts.multipleTypegates) {
328-
for (let i = 0; i < opts.multipleTypegates - 1; i++) {
329-
typegates.push(await Typegate.init(opts.syncConfig ?? null));
330-
}
339+
const replicas = opts.replicas ?? 1;
340+
if (replicas < 1) {
341+
throw new Error("replicas must be greater than 0");
342+
}
343+
if (replicas > 1 && opts.syncConfig == null) {
344+
throw new Error(
345+
"syncConfig must be provided when using multiple typegate instances",
346+
);
331347
}
348+
349+
const typegates = await Promise.all(
350+
Array.from({ length: replicas }).map((_) =>
351+
Typegate.init(opts.syncConfig ?? null)
352+
),
353+
);
354+
332355
const {
333356
systemTypegraphs = false,
334357
gitRepo = null,
335358
introspection = false,
336359
} = opts;
337360
if (systemTypegraphs) {
338-
await SystemTypegraph.loadAll(typegate);
361+
await Promise.all(
362+
typegates.map((typegate) => SystemTypegraph.loadAll(typegate)),
363+
);
339364
}
340365

341366
const mt = await MetaTest.init(
342367
t,
343-
typegates,
368+
new TypegateManager(typegates),
344369
introspection,
345370
opts.port != null,
346371
);

0 commit comments

Comments
 (0)