@nerest/nerest 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,6 +6,8 @@ React micro frontend framework
6
6
 
7
7
  ## Installation
8
8
 
9
+ TODO: update package
10
+
9
11
  ```
10
12
  npm i --save @nerest/nerest react react-dom
11
13
  ```
@@ -23,7 +25,7 @@ npm i --save @nerest/nerest react react-dom
23
25
 
24
26
  The `apps` directory must contain all of the apps provided by the micro frontend. E.g. `/apps/foo/index.tsx` is the entrypoint component of the `foo` app. It becomes available as the `/api/foo` route of the micro frontend server.
25
27
 
26
- See [nerest-harness](https://github.com/nerestjs/harness) for the minimal example of a nerest micro frontend.
28
+ See [nerest-harness](https://gitlab.tcsbank.ru/tj/nerest-harness) for the minimal example of a nerest micro frontend.
27
29
 
28
30
  ### Examples (`/examples/*.json`)
29
31
 
@@ -37,7 +39,7 @@ OpenAPI specification is compiled automatically based on the provided schemas an
37
39
 
38
40
  ## Configuration
39
41
 
40
- Different aspects of Nerest apps can be configured via environment variables, JSON configuration and runtime hooks written in TypeScript. Examples of all kinds of configuration can be viewed in the [nerest-harness](https://github.com/nerestjs/harness) repository.
42
+ Different aspects of Nerest apps can be configured via environment variables, JSON configuration and runtime hooks written in TypeScript. Examples of all kinds of configuration can be viewed in the [nerest-harness](https://gitlab.tcsbank.ru/tj/nerest-harness) repository.
41
43
 
42
44
  ### Environment Variables
43
45
 
@@ -47,8 +49,16 @@ Different aspects of Nerest apps can be configured via environment variables, JS
47
49
 
48
50
  #### Runtime
49
51
 
52
+ ##### Client
53
+
50
54
  All environment variables prefixed with `NEREST_` will be bundled with your app during buildtime. You can access them in the code using the special `import.meta.env` object. For example, `import.meta.env.NEREST_SOMEVAR` will be statically replaced during buildtime with the value of this environment variable on the build machine.
51
55
 
56
+ ##### Server
57
+
58
+ Additional environment variables which can be setup for a runtime:
59
+
60
+ - `ENABLE_K8S_PROBES`: activates additional routes `/livenessProbe` and `/readinessProbe` to check application status
61
+
52
62
  ### JSON Configuration
53
63
 
54
64
  TODO
@@ -66,4 +76,4 @@ npm install
66
76
  npm run build
67
77
  ```
68
78
 
69
- Use [nerest-harness](https://github.com/nerestjs/harness) to test changes locally.
79
+ Use [nerest-harness](https://gitlab.tcsbank.ru/tj/nerest-harness) to test changes locally.
@@ -9,11 +9,13 @@ const path_1 = __importDefault(require("path"));
9
9
  const vite_1 = __importDefault(require("vite"));
10
10
  const fastify_1 = __importDefault(require("fastify"));
11
11
  const static_1 = __importDefault(require("@fastify/static"));
12
+ const fastify_graceful_shutdown_1 = __importDefault(require("fastify-graceful-shutdown"));
12
13
  const apps_1 = require("./parts/apps");
13
14
  const render_1 = require("./parts/render");
14
15
  const preview_1 = require("./parts/preview");
15
16
  const validator_1 = require("./parts/validator");
16
17
  const swagger_1 = require("./parts/swagger");
18
+ const k8s_probes_1 = require("./parts/k8s-probes");
17
19
  async function runDevelopmentServer() {
18
20
  const root = process.cwd();
19
21
  // TODO: move build config into a separate file
@@ -119,6 +121,11 @@ async function runDevelopmentServer() {
119
121
  });
120
122
  }
121
123
  }
124
+ // Add graceful shutdown handler to prevent requests errors
125
+ await app.register(fastify_graceful_shutdown_1.default);
126
+ if (process.env.ENABLE_K8S_PROBES) {
127
+ await (0, k8s_probes_1.setupK8SProbes)(app);
128
+ }
122
129
  // TODO: only do this locally, load from CDN in production
123
130
  await app.register(static_1.default, {
124
131
  root: path_1.default.join(root, 'build'),
@@ -0,0 +1,2 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+ export declare function setupK8SProbes(app: FastifyInstance): Promise<void>;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setupK8SProbes = void 0;
4
+ // Setup routes for k8s probes to check if application is live
5
+ async function setupK8SProbes(app) {
6
+ // Handler for graceful shutdowns
7
+ // K8s can initiate shutdown at any moment: on pods restart or on deploy.
8
+ // So, if we receive shutdown request, we:
9
+ // - starts to send 503 response code on readiness probes to stop receiving requests
10
+ // - finishes all current requests
11
+ // - shuts down the server
12
+ let isShutdownInProgress = false;
13
+ app.gracefulShutdown((code, next) => {
14
+ // TODO: replace with nerest logger, when it'll be ready
15
+ console.log('Graceful shutdown in process...');
16
+ isShutdownInProgress = true;
17
+ next();
18
+ });
19
+ app.get('/livenessProbe', { logLevel: 'silent' }, (req, res) => {
20
+ res.status(200).send();
21
+ });
22
+ app.get('/readinessProbe', { logLevel: 'silent' }, (req, res) => {
23
+ if (isShutdownInProgress) {
24
+ res.status(503).send({ status: 'Shutdown in progress' });
25
+ }
26
+ else {
27
+ res.status(200).send();
28
+ }
29
+ });
30
+ }
31
+ exports.setupK8SProbes = setupK8SProbes;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nerest/nerest",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "React micro frontend framework",
5
5
  "homepage": "https://github.com/nerestjs/nerest#readme",
6
6
  "repository": {
@@ -55,6 +55,7 @@
55
55
  "dotenv": "^16.1.4",
56
56
  "fast-uri": "^2.2.0",
57
57
  "fastify": "^4.17.0",
58
+ "fastify-graceful-shutdown": "^3.5.1",
58
59
  "nanoid": "^3.3.6",
59
60
  "vite": "^4.3.9"
60
61
  },
@@ -9,12 +9,14 @@ import type { RollupWatcher, RollupWatcherEvent } from 'rollup';
9
9
  import type { RouteShorthandOptions } from 'fastify';
10
10
  import fastify from 'fastify';
11
11
  import fastifyStatic from '@fastify/static';
12
+ import fastifyGracefulShutdown from 'fastify-graceful-shutdown';
12
13
 
13
14
  import { loadApps } from './parts/apps';
14
15
  import { renderApp } from './parts/render';
15
16
  import { renderPreviewPage } from './parts/preview';
16
17
  import { validator } from './parts/validator';
17
18
  import { setupSwagger } from './parts/swagger';
19
+ import { setupK8SProbes } from './parts/k8s-probes';
18
20
 
19
21
  export async function runDevelopmentServer() {
20
22
  const root = process.cwd();
@@ -148,6 +150,13 @@ export async function runDevelopmentServer() {
148
150
  }
149
151
  }
150
152
 
153
+ // Add graceful shutdown handler to prevent requests errors
154
+ await app.register(fastifyGracefulShutdown);
155
+
156
+ if (process.env.ENABLE_K8S_PROBES) {
157
+ await setupK8SProbes(app);
158
+ }
159
+
151
160
  // TODO: only do this locally, load from CDN in production
152
161
  await app.register(fastifyStatic, {
153
162
  root: path.join(root, 'build'),
@@ -0,0 +1,30 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+
3
+ // Setup routes for k8s probes to check if application is live
4
+ export async function setupK8SProbes(app: FastifyInstance) {
5
+ // Handler for graceful shutdowns
6
+ // K8s can initiate shutdown at any moment: on pods restart or on deploy.
7
+ // So, if we receive shutdown request, we:
8
+ // - starts to send 503 response code on readiness probes to stop receiving requests
9
+ // - finishes all current requests
10
+ // - shuts down the server
11
+ let isShutdownInProgress = false;
12
+ app.gracefulShutdown((code, next) => {
13
+ // TODO: replace with nerest logger, when it'll be ready
14
+ console.log('Graceful shutdown in process...');
15
+ isShutdownInProgress = true;
16
+ next();
17
+ });
18
+
19
+ app.get('/livenessProbe', { logLevel: 'silent' }, (req, res) => {
20
+ res.status(200).send();
21
+ });
22
+
23
+ app.get('/readinessProbe', { logLevel: 'silent' }, (req, res) => {
24
+ if (isShutdownInProgress) {
25
+ res.status(503).send({ status: 'Shutdown in progress' });
26
+ } else {
27
+ res.status(200).send();
28
+ }
29
+ });
30
+ }
@@ -3,6 +3,7 @@ import path from 'path';
3
3
  import fs from 'fs/promises';
4
4
 
5
5
  import fastify from 'fastify';
6
+ import fastifyGracefulShutdown from 'fastify-graceful-shutdown';
6
7
  import type { RouteShorthandOptions } from 'fastify';
7
8
 
8
9
  import type { AppEntry } from './parts/apps';
@@ -10,6 +11,7 @@ import { renderApp } from './parts/render';
10
11
  import { setupSwagger } from './parts/swagger';
11
12
  import { validator } from './parts/validator';
12
13
  import { renderPreviewPage } from './parts/preview';
14
+ import { setupK8SProbes } from './parts/k8s-probes';
13
15
 
14
16
  // TODO: refactor to merge the similar parts between production and development server?
15
17
  async function runProductionServer() {
@@ -22,6 +24,7 @@ async function runProductionServer() {
22
24
  })
23
25
  ) as Record<string, AppEntry>;
24
26
 
27
+ // TODO: fix client-side vite types
25
28
  const components = import.meta.glob('/apps/*/index.tsx', {
26
29
  import: 'default',
27
30
  eager: true,
@@ -93,6 +96,13 @@ async function runProductionServer() {
93
96
  }
94
97
  }
95
98
 
99
+ // Add graceful shutdown handler to prevent requests errors
100
+ await app.register(fastifyGracefulShutdown);
101
+
102
+ if (process.env.ENABLE_K8S_PROBES) {
103
+ await setupK8SProbes(app);
104
+ }
105
+
96
106
  // TODO: remove hardcoded port
97
107
  await app.listen({
98
108
  host: '0.0.0.0',