Skip to content

Commit 4522070

Browse files
committed
feat: improve docker for deployment
1 parent bf69d6c commit 4522070

14 files changed

+191
-164
lines changed

deployment/Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ WORKDIR /app-explorer
1616

1717
RUN pnpm install --frozen-lockfile
1818

19-
EXPOSE 4444
19+
EXPOSE ${PORT}
2020

2121
WORKDIR /app-explorer/packages/graphql
2222

packages/graphql/.env.example

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
FUEL_PROVIDER_BETA5=https://beta-5.fuel.network/graphql
2-
SERVER_PORT=4000
1+
FUEL_PROVIDER=https://beta-5.fuel.network/graphql
2+
SERVER_PORT=4444

packages/graphql/.env.production

+2-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
FUEL_PROVIDER_BETA5=https://beta-5.fuel.network/graphql
1+
FUEL_PROVIDER=https://beta-5.fuel.network/graphql
2+
SERVER_PORT=4444

packages/graphql/codegen.fuel.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import type { CodegenConfig } from '@graphql-codegen/cli';
22

3-
console.log(`process.env.FUEL_PROVIDER_BETA5`, process.env.FUEL_PROVIDER_BETA5);
3+
import { requireEnv } from './src/utils/requireEnv';
4+
5+
const { FUEL_PROVIDER } = requireEnv(['FUEL_PROVIDER']);
46

57
const config: CodegenConfig = {
68
generates: {
79
'./src/schemas/fuelcore.graphql': {
8-
schema:
9-
process.env.FUEL_PROVIDER_BETA5 ||
10-
'https://beta-5.fuel.network/graphql',
10+
schema: FUEL_PROVIDER,
1111
plugins: ['schema-ast'],
1212
config: {
1313
includeDirectives: true,

packages/graphql/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
"codegen:fuel": "gql-gen -r dotenv/config --config codegen.fuel.ts",
1616
"codegen:app": "gql-gen -r dotenv/config --config codegen.ts",
1717
"dev": "pnpm build:watch",
18-
"start": "pnpm dev",
1918
"fix:generated": "node ./scripts/fix-generated.mjs",
2019
"ts:check": "tsc --noEmit",
2120
"prepare": "pnpm build"
@@ -43,7 +42,8 @@
4342
"graphql-tag": "2.12.6",
4443
"lodash": "^4.17.21",
4544
"tai64": "1.0.0",
46-
"typescript": "5.3.3"
45+
"typescript": "5.3.3",
46+
"wait-port": "1.1.0"
4747
},
4848
"devDependencies": {
4949
"@babel/cli": "7.23.9",

packages/graphql/src/bin.ts

-73
This file was deleted.

packages/graphql/src/bin/index.ts

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { runDevelopment, runServer } from './server';
2+
3+
const { WATCH } = process.env;
4+
5+
if (WATCH === 'true') {
6+
runDevelopment();
7+
} else {
8+
runServer();
9+
}

packages/graphql/src/bin/server.ts

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import chokidar from 'chokidar';
2+
import { execa } from 'execa';
3+
import { createServer } from 'http';
4+
import { resolve } from 'path';
5+
6+
import app from '../server';
7+
import { requireEnv } from '../utils/requireEnv';
8+
9+
const { SERVER_PORT = 4444 } = requireEnv(['SERVER_PORT']);
10+
11+
const server = createServer(app);
12+
13+
export async function runServer() {
14+
return new Promise((resolve) => {
15+
server.listen(SERVER_PORT, async () => {
16+
console.log(
17+
`🚀 Server running at http://localhost:${SERVER_PORT}/graphql`
18+
);
19+
resolve(null);
20+
});
21+
});
22+
}
23+
24+
export async function closeServer() {
25+
return new Promise((resolve) => {
26+
server.close(() => {
27+
resolve(null);
28+
console.log('🛑 GraphQL server stopped!');
29+
});
30+
});
31+
}
32+
33+
export async function runDevelopment() {
34+
const cwd = resolve(__dirname, '../');
35+
const gqlWatcher = chokidar.watch(['src/**/*.graphql'], {
36+
cwd,
37+
ignoreInitial: true,
38+
ignored: ['src/schemas'],
39+
});
40+
41+
async function codegen() {
42+
console.log('⌛️ Generating GraphQL code...');
43+
try {
44+
await execa('pnpm', ['codegen:app'], { stdio: 'inherit' });
45+
console.log('✅ GraphQL code generated!');
46+
} catch (err) {
47+
console.log('❌ GraphQL error!');
48+
}
49+
50+
console.log('👀 Watching for GraphQL changes...');
51+
}
52+
53+
await runServer();
54+
await codegen();
55+
56+
async function exitHandler() {
57+
await closeServer();
58+
gqlWatcher.close();
59+
}
60+
61+
process.on('exit', exitHandler);
62+
process.on('SIGTERM', exitHandler);
63+
process.on('SIGINT', exitHandler);
64+
process.on('SIGUSR1', exitHandler);
65+
66+
gqlWatcher.on('all', async () => {
67+
await closeServer();
68+
await runServer();
69+
await codegen();
70+
});
71+
72+
return exitHandler;
73+
}
+11-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
11
import { Provider } from 'fuels';
22

3+
import { Cache } from '../utils';
4+
5+
const CHAIN_CACHE = 43200000;
6+
37
export class NetworkDomain {
8+
static cache = new Cache();
9+
410
static async getChainInfo(url: string) {
5-
const provider = await Provider.create(url);
11+
let provider = this.cache.get<Provider>(url);
12+
if (!provider) {
13+
provider = await Provider.create(url);
14+
}
15+
this.cache.put(url, provider, CHAIN_CACHE);
616
return provider.getChain();
717
}
818
}

packages/graphql/src/server.ts

+24-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import { createSchema } from './schema';
88
import { createGraphqlFetch } from './utils/executor';
99
import { requireEnv } from './utils/requireEnv';
1010

11-
const { FUEL_PROVIDER_BETA5 } = requireEnv(['FUEL_PROVIDER_BETA5']);
11+
const { FUEL_PROVIDER = 'https://beta-5.fuel.network/graphql' } = requireEnv([
12+
'FUEL_PROVIDER',
13+
]);
1214

1315
// Create a server:
1416
const app = express();
@@ -26,17 +28,36 @@ app.get(
2628
})
2729
);
2830

29-
const executor = createGraphqlFetch(FUEL_PROVIDER_BETA5);
31+
const executor = createGraphqlFetch(FUEL_PROVIDER);
3032
const schema = createSchema(executor);
3133

3234
app.post(
3335
'/graphql',
3436
createHandler({
3537
schema,
3638
async context() {
37-
return ContextDomain.createContext(FUEL_PROVIDER_BETA5);
39+
return ContextDomain.createContext(FUEL_PROVIDER);
3840
},
3941
})
4042
);
4143

44+
// Check health of the graphql endpoint and the fuel provider
45+
app.get('/health', async (_, res) => {
46+
let providerUp = null;
47+
try {
48+
providerUp = (
49+
await fetch(`${FUEL_PROVIDER.replace('/graphql', '/health')}`).then(
50+
(res) => res.json()
51+
)
52+
).up;
53+
} catch (e) {
54+
providerUp = false;
55+
}
56+
57+
res.status(200).send({
58+
up: true,
59+
providerUp: providerUp,
60+
});
61+
});
62+
4263
export default app;

packages/graphql/src/utils/cache.ts

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
export class Cache {
2+
private _cache: Record<string, { value: unknown; expire: number }> = {};
3+
4+
put<T>(key: string, value: T, ttl: number) {
5+
const expire = Date.now() + ttl;
6+
this._cache[key] = { value, expire };
7+
}
8+
9+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
10+
get<T = any>(key: string): T | null {
11+
const data = this._cache[key];
12+
if (data) {
13+
if (Date.now() < data.expire) {
14+
return data.value as T;
15+
} else {
16+
delete this._cache[key];
17+
}
18+
}
19+
return null;
20+
}
21+
22+
delete(key: string) {
23+
delete this._cache[key];
24+
}
25+
}

packages/graphql/src/utils/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from './executor';
22
export * from './getFieldsValues';
3+
export * from './cache';

packages/graphql/tsup.config.mjs

+22-17
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import getPort from 'get-port';
44
import { defineConfig } from 'tsup';
55

66
const graphqlLoaderPlugin = graphqlLoaderPluginPkg.default;
7+
// Assign a single port for the process
8+
const port = await getPort({ port: 4444 });
79

810
export default defineConfig((options) => ({
911
outDir: 'dist',
@@ -12,23 +14,26 @@ export default defineConfig((options) => ({
1214
sourcemap: true,
1315
clean: false,
1416
esbuildPlugins: [graphqlLoaderPlugin()],
15-
entry: { index: 'src/bin.ts' },
17+
entry: { index: 'src/bin/index.ts' },
1618
async onSuccess() {
17-
const port = await getPort({ port: 4444 });
18-
const cmd = execa('node', ['--import', 'tsx/esm', './dist/index.js'], {
19-
stdio: 'inherit',
20-
cleanup: true,
21-
env: {
22-
SERVER_PORT: port,
23-
WATCH: Boolean(options.watch),
24-
FUEL_PROVIDER_BETA5:
25-
process.env.FUEL_PROVIDER_BETA5 ||
26-
'https://beta-5.fuel.network/graphql',
27-
},
28-
});
29-
30-
return () => {
31-
cmd.kill('SIGTERM');
32-
};
19+
if (options.watch) {
20+
const cmd = execa('node', ['--import', 'tsx/esm', './dist/index.js'], {
21+
stdio: 'inherit',
22+
cleanup: true,
23+
env: {
24+
SERVER_PORT: port,
25+
WATCH: Boolean(options.watch),
26+
FUEL_PROVIDER: process.env.FUEL_PROVIDER,
27+
},
28+
});
29+
// Wait process to close until restarting
30+
return async () => {
31+
const killProcess = new Promise((resolve) => {
32+
cmd.on('close', () => resolve(true));
33+
});
34+
cmd.kill('SIGTERM');
35+
await killProcess;
36+
};
37+
}
3338
},
3439
}));

0 commit comments

Comments
 (0)