Skip to content

Commit

Permalink
feat: enable run modes (#116)
Browse files Browse the repository at this point in the history
* feat: enable run modes

* docs: readme
  • Loading branch information
rafaelcr committed Feb 21, 2023
1 parent 6457378 commit c7a9c55
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 16 deletions.
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,13 @@ Stacks blockchain and exposes it via JSON REST API endpoints.
* Easy to use REST JSON endpoints with ETag caching
* Prometheus metrics for job queue status, contract and token counts, API performance, etc.
* Image cache/CDN support
* Run modes for auto-scaling

## API reference

See the [Token Metadata Service API Reference]() for more information.
See the [Token Metadata Service API
Reference](https://token-metadata-service-pbcblockstack-blockstack.vercel.app/) for more
information.

## Quick start

Expand Down Expand Up @@ -79,6 +82,19 @@ Start the service
npm run start
```

#### Run modes

To better support auto-scaling server configurations, this service supports three run modes
specified by the `RUN_MODE` environment variable:

* `default`: Runs all background jobs and the API server. Use this when you're running this service
only on one instance. This is the default mode.
* `readonly`: Runs only the API server. Use this in an auto-scaled cluster when you have multiple
`readonly` instances and just one `writeonly` instance. This mode needs a `writeonly` instance to
continue populating the token metadata DB.
* `writeonly`: Use one of these in an auto-scaled environment so you can continue consuming new
token contracts. Use in conjunction with multiple `readonly` instances as explained above.

### Stopping the service

When shutting down, you should always prefer to send the `SIGINT` signal instead of `SIGKILL` so
Expand Down
14 changes: 14 additions & 0 deletions src/env.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import envSchema from 'env-schema';

interface Env {
/**
* Run mode for this service. Allows you to control how the Token Metadata Service runs, typically
* in an auto-scaled environment. Available values are:
* * `default`: Runs background jobs and the REST API server (this is the default)
* * `writeonly`: Runs only background jobs
* * `readonly`: Runs only the REST API server
*/
RUN_MODE: string;
/** Hosname of the Token Metadata Service API server */
API_HOST: string;
/** Port in which to serve the API */
Expand Down Expand Up @@ -109,6 +117,7 @@ export function getEnvVars(): Env {
const schema = {
type: 'object',
required: [
'RUN_MODE',
'API_HOST',
'API_PORT',
'PGHOST',
Expand All @@ -127,6 +136,11 @@ export function getEnvVars(): Env {
'PUBLIC_GATEWAY_ARWEAVE',
],
properties: {
RUN_MODE: {
type: 'string',
enum: ['default', 'readonly', 'writeonly'],
default: 'default',
},
API_HOST: {
type: 'string',
},
Expand Down
54 changes: 39 additions & 15 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@ import { registerShutdownConfig } from './shutdown-handler';
import { ENV } from './env';
import { logger } from './logger';

async function initApp() {
const db = await PgStore.connect({ skipMigrations: false });
/**
* Initializes background services. Only for `default` and `writeonly` run modes.
* @param db - PgStore
*/
async function initBackgroundServices(db: PgStore) {
logger.info('Initializing background services...');
const apiDb = await PgBlockchainApiStore.connect();

if (process.env.NODE_ENV === 'production') {
Expand Down Expand Up @@ -53,35 +57,55 @@ async function initApp() {
},
});

const apiServer = await buildApiServer({ db });
registerShutdownConfig({
name: 'API Server',
name: 'Blockchain API DB',
forceKillable: false,
handler: async () => {
await apiServer.close();
await apiDb.close();
},
});

await contractImporter.import();
await contractMonitor.start();
jobQueue.start();
}

/**
* Initializes API service. Only for `default` and `readonly` run modes.
* @param db - PgStore
*/
async function initApiService(db: PgStore) {
logger.info('Initializing API service...');
const apiServer = await buildApiServer({ db });
registerShutdownConfig({
name: 'DB',
name: 'API Server',
forceKillable: false,
handler: async () => {
await db.close();
await apiServer.close();
},
});

await apiServer.listen({ host: ENV.API_HOST, port: ENV.API_PORT });
}

async function initApp() {
logger.info(`Initializing in ${ENV.RUN_MODE} run mode...`);
const db = await PgStore.connect({ skipMigrations: false });

if (['default', 'writeonly'].includes(ENV.RUN_MODE)) {
await initBackgroundServices(db);
}
if (['default', 'readonly'].includes(ENV.RUN_MODE)) {
await initApiService(db);
}

registerShutdownConfig({
name: 'Blockchain API DB',
name: 'DB',
forceKillable: false,
handler: async () => {
await apiDb.close();
await db.close();
},
});

// Start services.
await contractImporter.import();
await contractMonitor.start();
jobQueue.start();
await apiServer.listen({ host: ENV.API_HOST, port: ENV.API_PORT });
}

registerShutdownConfig();
Expand Down

0 comments on commit c7a9c55

Please sign in to comment.