Skip to content

Commit

Permalink
refactor: cleanup code and update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
0xnigir1 committed Nov 4, 2024
1 parent a9e835d commit 8b5afdb
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 59 deletions.
38 changes: 28 additions & 10 deletions apps/processor/README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
# TODO: update README
# Processor Service

> Note: use this app as reference but preferred way is to re-write app
> from zero instead of refactoring this one.
> When you don't need this anymore, you can delete it
This service is the main application that runs the core processing pipeline:

Sample app that uses [sample-lib](../../packages/sample-lib) Blockchain
provider to fetch Vitalik and Zero address native balance and sums them
- Instantiates and coordinates components from [Grants Stack Indexer packages](../../packages/)
- Creates and manages an Orchestrator per chain to process blockchain events

## Requirements

- A running instance of PostgreSQL Data Layer with migrations applied
- A running instance of Envio Indexer

## Setup

1. Change package name to your own in [`package.json`](./package.json)
2. Install dependencies running `pnpm install`
1. Install dependencies running `pnpm install`
2. Build the app using `pnpm build`

### ⚙️ Setting up env variables

Expand All @@ -23,7 +26,17 @@ $ cp .env.example .env
Available options:
| Name | Description | Default | Required | Notes |
|-----------------------------|--------------------------------------------------------------------------------------------------------------------------------|-----------|----------------------------------|-----------------------------------------------------------------|
| `RPC_URL` | RPC URL to use for querying balances | N/A | Yes | |
| `RPC_URLS` | Array of RPC URLs | N/A | Yes | Multiple URLs for redundancy |
| `CHAIN_ID` | Chain ID | N/A | Yes | At the moment only Optimism is supported (10) |
| `FETCH_LIMIT` | Maximum number of items to fetch in one batch | 500 | Yes | |
| `FETCH_DELAY_MS` | Delay between fetch operations in milliseconds | 3000 | Yes | |
| `DATABASE_URL` | PostgreSQL Data Layer database connection URL | N/A | Yes | |
| `DATABASE_SCHEMA` | PostgreSQL Data Layer database schema name | chainDataSchema | Yes | |
| `INDEXER_GRAPHQL_URL` | GraphQL endpoint for the indexer | N/A | Yes | |
| `INDEXER_ADMIN_SECRET` | Admin secret for indexer authentication | N/A | Yes | |
| `IPFS_GATEWAYS_URL` | Array of IPFS gateway URLs | N/A | Yes | Multiple gateways for redundancy |
| `COINGECKO_API_KEY` | API key for CoinGecko service | N/A | Yes | |
| `COINGECKO_API_TYPE` | CoinGecko API tier (demo or pro) | N/A | Yes | |

## Available Scripts

Expand All @@ -34,10 +47,15 @@ Available scripts that can be run using `pnpm`:
| `build` | Build library using tsc |
| `check-types` | Check types issues using tsc |
| `clean` | Remove `dist` folder |
| `dev` | Run the app in development mode using tsx |
| `dev:watch` | Run the app in watch mode for development |
| `lint` | Run ESLint to check for coding standards |
| `lint:fix` | Run linter and automatically fix code formatting issues |
| `format` | Check code formatting and style using Prettier |
| `format:fix` | Run formatter and automatically fix issues |
| `start` | Run the app |
| `start` | Run the compiled app from dist folder |
| `test` | Run tests using vitest |
| `test:cov` | Run tests with coverage report |

TODO: e2e tests
TODO: Docker image
3 changes: 2 additions & 1 deletion apps/processor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"build": "tsc -p tsconfig.build.json",
"check-types": "tsc --noEmit -p ./tsconfig.json",
"clean": "rm -rf dist",
"dev": "tsx watch src/index.ts",
"dev": "tsx src/index.ts",
"dev:watch": "tsx watch src/index.ts",
"format": "prettier --check \"{src,test}/**/*.{js,ts,json}\"",
"format:fix": "prettier --write \"{src,test}/**/*.{js,ts,json}\"",
"lint": "eslint \"{src,test}/**/*.{js,ts,json}\"",
Expand Down
19 changes: 12 additions & 7 deletions apps/processor/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import { inspect } from "util";
import { environment } from "./config/index.js";
import { ProcessorService } from "./services/processor.service.js";

let processor: ProcessorService;

const main = async (): Promise<void> => {
const processor = new ProcessorService(environment);
processor = new ProcessorService(environment);
await processor.start();
};

// Handle uncaught errors
process.on("unhandledRejection", (reason, p) => {
console.error(`Unhandled Rejection at: \n${inspect(p, undefined, 100)}, \nreason: ${reason}`);
process.exit(1);
Expand All @@ -21,8 +22,12 @@ process.on("uncaughtException", (error: Error) => {
process.exit(1);
});

// Start the application
main().catch((err) => {
console.error(`Caught error in main handler: ${err}`);
process.exit(1);
});
main()
.catch((err) => {
console.error(`Caught error in main handler: ${err}`);
process.exit(1);
})
// eslint-disable-next-line @typescript-eslint/no-misused-promises
.finally(async () => {
await processor?.releaseResources();
});
2 changes: 2 additions & 0 deletions apps/processor/src/services/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./sharedDependencies.service.js";
export * from "./processor.service.js";
19 changes: 0 additions & 19 deletions apps/processor/src/services/logger.service.ts

This file was deleted.

53 changes: 44 additions & 9 deletions apps/processor/src/services/processor.service.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,52 @@
import { optimism } from "viem/chains";

import { EvmProvider } from "@grants-stack-indexer/chain-providers";
import { Orchestrator } from "@grants-stack-indexer/data-flow";
import { ChainId } from "@grants-stack-indexer/shared";
import { ChainId, Logger } from "@grants-stack-indexer/shared";

import { Environment } from "../config/env.js";
import { DependenciesService } from "./dependencies.service.js";
import { Logger } from "./logger.service.js";
import { SharedDependencies, SharedDependenciesService } from "./index.js";

/**
* Processor service application
* - Initializes core dependencies (repositories, providers) via SharedDependenciesService
* - Sets up EVM provider with configured RPC endpoints
* - Creates an Orchestrator instance to coordinate an specific chain:
* - Fetching on-chain events via indexer client
* - Processing events through registered handlers
* - Storing processed data in PostgreSQL via repositories
* - Manages graceful shutdown on termination signals
*
* TODO: support multichain
*/
export class ProcessorService {
private readonly logger = new Logger();
private readonly logger = Logger.getInstance();
private readonly orchestrator: Orchestrator;
private readonly kyselyDatabase: SharedDependencies["kyselyDatabase"];

constructor(private readonly env: Environment) {
const { core, registries, indexerClient } = DependenciesService.initialize(
env,
this.logger,
);
const { core, registries, indexerClient, kyselyDatabase } =
SharedDependenciesService.initialize(env);
this.kyselyDatabase = kyselyDatabase;

// Initialize EVM provider
const evmProvider = new EvmProvider(env.RPC_URLS, optimism, this.logger);

this.orchestrator = new Orchestrator(
env.CHAIN_ID as ChainId,
core,
{ ...core, evmProvider },
indexerClient,
registries,
env.FETCH_LIMIT,
env.FETCH_DELAY_MS,
);
}

/**
* Start the processor service
*
* The processor runs indefinitely until it is terminated.
*/
async start(): Promise<void> {
this.logger.info("Starting processor service...");

Expand All @@ -48,4 +70,17 @@ export class ProcessorService {
throw error;
}
}

/**
* Call this function when the processor service is terminated
* - Releases database resources
*/
async releaseResources(): Promise<void> {
try {
this.logger.info("Releasing resources...");
await this.kyselyDatabase.destroy();
} catch (error) {
this.logger.error(`Error releasing resources: ${error}`);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import { optimism } from "viem/chains";

import { EvmProvider } from "@grants-stack-indexer/chain-providers";
import {
CoreDependencies,
InMemoryEventsRegistry,
Expand All @@ -15,24 +12,27 @@ import {
KyselyProjectRepository,
KyselyRoundRepository,
} from "@grants-stack-indexer/repository";
import { ILogger } from "@grants-stack-indexer/shared";

import { Environment } from "../config/index.js";

export type Dependencies = {
core: CoreDependencies;
export type SharedDependencies = {
core: Omit<CoreDependencies, "evmProvider">;
registries: {
eventsRegistry: InMemoryEventsRegistry;
strategyRegistry: InMemoryStrategyRegistry;
};
indexerClient: EnvioIndexerClient;
kyselyDatabase: ReturnType<typeof createKyselyDatabase>;
};

export class DependenciesService {
static initialize(env: Environment, logger: ILogger): Dependencies {
// Initialize EVM provider
const evmProvider = new EvmProvider(env.RPC_URLS, optimism, logger);

/**
* Shared dependencies service
* - Initializes core dependencies (repositories, providers)
* - Initializes registries
* - Initializes indexer client
*/
export class SharedDependenciesService {
static initialize(env: Environment): SharedDependencies {
// Initialize repositories
const kyselyDatabase = createKyselyDatabase({
connectionString: env.DATABASE_URL,
Expand Down Expand Up @@ -63,7 +63,6 @@ export class DependenciesService {

return {
core: {
evmProvider,
projectRepository,
roundRepository,
applicationRepository,
Expand All @@ -75,6 +74,7 @@ export class DependenciesService {
strategyRegistry,
},
indexerClient,
kyselyDatabase,
};
}
}
3 changes: 2 additions & 1 deletion packages/shared/src/external.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ export {

export type { DeepPartial } from "./utils/testing.js";
export { mergeDeep } from "./utils/testing.js";
export type { ILogger, Logger } from "./internal.js";
export type { ILogger } from "./logger/logger.interface.js";
export { Logger } from "./logger/logger.js";

export { BigNumber } from "./internal.js";
export type { BigNumberType } from "./internal.js";
Expand Down

0 comments on commit 8b5afdb

Please sign in to comment.