Skip to content

Commit

Permalink
feat(dependency-store): implement dependency store with new sdk
Browse files Browse the repository at this point in the history
  • Loading branch information
gjuchault committed Jan 10, 2024
1 parent 4a1931f commit 4125e56
Show file tree
Hide file tree
Showing 20 changed files with 238 additions and 149 deletions.
5 changes: 5 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
"type": "shell",
"command": "${workspaceRoot}/node_modules/tsx/dist/cli.mjs",
"args": ["--test", "${relativeFile}"],
"presentation": {
"clear": true,
"showReuseMessage": false,
"echo": false
},
"group": {
"kind": "test",
"isDefault": true
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
"@fastify/multipart": "^8.1.0",
"@fastify/rate-limit": "^9.1.0",
"@fastify/under-pressure": "^8.3.0",
"@gjuchault/typescript-service-sdk": "^6.0.1",
"@gjuchault/typescript-service-sdk": "^6.3.0",
"@opentelemetry/api": "^1.7.0",
"@opentelemetry/core": "^1.19.0",
"@opentelemetry/exporter-prometheus": "^0.46.0",
Expand Down
46 changes: 28 additions & 18 deletions src/application/healthcheck/__tests__/get-healthcheck.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import * as assert from "node:assert/strict";
import { before, describe, it, mock } from "node:test";

import type { Redis } from "ioredis";
import { err, ok } from "neverthrow";

import type { HealthcheckRepository } from "~/repository/healthcheck/index.js";
import { buildMockDependencyStore } from "~/test-helpers/mock.js";

import { getHealthcheck, GetHealthcheckResult } from "../get-healthcheck.js";

Expand All @@ -16,23 +18,25 @@ const mockUnhealthyCache = {
} as unknown as Redis;

const mockHealthyRepository: HealthcheckRepository = {
getHealthcheck: mock.fn(() => Promise.resolve({ outcome: "healthy" })),
getHealthcheck: mock.fn(() => Promise.resolve(ok("healthy"))),
};

const mockUnhealthyRepository: HealthcheckRepository = {
getHealthcheck: mock.fn(() => Promise.resolve({ outcome: "unhealthy" })),
getHealthcheck: mock.fn(() => Promise.resolve(err("databaseError"))),
};

await describe("getHealthcheck()", async () => {
await describe("given a healthy cache and database", async () => {
const dependencyStore = buildMockDependencyStore({
cache: mockHealthyCache,
repository: { healthcheck: mockHealthyRepository },
});

await describe("when called", async () => {
let result: GetHealthcheckResult;

before(async () => {
result = await getHealthcheck({
cache: mockHealthyCache,
healthcheckRepository: mockHealthyRepository,
});
result = await getHealthcheck({ dependencyStore });
});

await it("returns healthy", () => {
Expand All @@ -49,14 +53,16 @@ await describe("getHealthcheck()", async () => {
});

await describe("given an unhealthy cache and healthy database", async () => {
const dependencyStore = buildMockDependencyStore({
cache: mockUnhealthyCache,
repository: { healthcheck: mockHealthyRepository },
});

await describe("when called", async () => {
let result: GetHealthcheckResult;

before(async () => {
result = await getHealthcheck({
cache: mockUnhealthyCache,
healthcheckRepository: mockHealthyRepository,
});
result = await getHealthcheck({ dependencyStore });
});

await it("returns unhealthy cache, healthy database", () => {
Expand All @@ -73,14 +79,16 @@ await describe("getHealthcheck()", async () => {
});

await describe("given a healthy cache and unhealthy database", async () => {
const dependencyStore = buildMockDependencyStore({
cache: mockHealthyCache,
repository: { healthcheck: mockUnhealthyRepository },
});

await describe("when called", async () => {
let result: GetHealthcheckResult;

before(async () => {
result = await getHealthcheck({
cache: mockHealthyCache,
healthcheckRepository: mockUnhealthyRepository,
});
result = await getHealthcheck({ dependencyStore });
});

await it("returns unhealthy cache, healthy database", () => {
Expand All @@ -97,14 +105,16 @@ await describe("getHealthcheck()", async () => {
});

await describe("given a healthy cache and database", async () => {
const dependencyStore = buildMockDependencyStore({
cache: mockUnhealthyCache,
repository: { healthcheck: mockUnhealthyRepository },
});

await describe("when called", async () => {
let result: GetHealthcheckResult;

before(async () => {
result = await getHealthcheck({
cache: mockUnhealthyCache,
healthcheckRepository: mockUnhealthyRepository,
});
result = await getHealthcheck({ dependencyStore });
});

await it("returns unhealthy cache, healthy database", () => {
Expand Down
9 changes: 7 additions & 2 deletions src/application/healthcheck/__tests__/get-users.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ok } from "neverthrow";

import type { UserEmail, UserId, UserName } from "~/domain/user.js";
import type { UserRepository } from "~/repository/user/index.js";
import { buildMockDependencyStore } from "~/test-helpers/mock.js";

import { getUsers, GetUsersResult } from "../get-users.js";

Expand All @@ -24,13 +25,17 @@ const mockRepository: UserRepository = {
};

await describe("getUsers()", async () => {
await describe("given a healthy cache and database", async () => {
await describe("given a repository", async () => {
const dependencyStore = buildMockDependencyStore({
repository: { user: mockRepository },
});

await describe("when called", async () => {
let result: GetUsersResult;

before(async () => {
result = await getUsers({
userRepository: mockRepository,
dependencyStore,
});
});

Expand Down
19 changes: 11 additions & 8 deletions src/application/healthcheck/get-healthcheck.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import os from "node:os";
import v8 from "node:v8";

import type { Redis } from "ioredis";

import type { HealthcheckRepository } from "~/repository/healthcheck/index.js";
import { DependencyStore } from "~/store";

export interface GetHealthcheckResult {
database: "healthy" | "unhealthy";
Expand All @@ -13,12 +11,14 @@ export interface GetHealthcheckResult {
}

export async function getHealthcheck({
healthcheckRepository,
cache,
dependencyStore,
}: {
healthcheckRepository: HealthcheckRepository;
cache: Redis;
dependencyStore: DependencyStore;
}): Promise<GetHealthcheckResult> {
const cache = dependencyStore.get("cache");
const { healthcheck: healthcheckRepository } =
dependencyStore.get("repository");

const databaseResult = await healthcheckRepository.getHealthcheck();

let cacheResult: "healthy" | "unhealthy" = "healthy";
Expand All @@ -36,7 +36,10 @@ export async function getHealthcheck({
v8HeapStatistics.total_heap_size / v8HeapStatistics.heap_size_limit;

return {
database: databaseResult.outcome,
database: databaseResult.match(
() => "healthy",
() => "unhealthy",
),
cache: cacheResult,
systemMemory: systemMemoryUsage > 0.8 ? "unhealthy" : "healthy",
processMemory: processMemoryUsage > 0.8 ? "unhealthy" : "healthy",
Expand Down
11 changes: 5 additions & 6 deletions src/application/healthcheck/get-users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,20 @@ import type { NonEmptyArray } from "@gjuchault/typescript-service-sdk";
import type { Result } from "neverthrow";

import type { User } from "~/domain/user.js";
import type {
GetUsersError as GetUsersRepositoryError,
UserRepository,
} from "~/repository/user/index.js";
import type { GetUsersError as GetUsersRepositoryError } from "~/repository/user/index.js";
import { DependencyStore } from "~/store";

export type GetUsersResult = Result<
NonEmptyArray<User>,
GetUsersRepositoryError
>;

export async function getUsers({
userRepository,
dependencyStore,
}: {
userRepository: UserRepository;
dependencyStore: DependencyStore;
}): Promise<GetUsersResult> {
const { user: userRepository } = dependencyStore.get("repository");
const users = await userRepository.get();

return users;
Expand Down
19 changes: 3 additions & 16 deletions src/application/healthcheck/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
import type {
Cache,
DependencyStore,
TaskScheduling,
} from "@gjuchault/typescript-service-sdk";

import type { Repository } from "~/repository/index.js";
import { DependencyStore } from "~/store.js";

import type { GetHealthcheckResult } from "./get-healthcheck.js";
import { getHealthcheck } from "./get-healthcheck.js";
Expand All @@ -18,11 +12,7 @@ export async function createHealthcheckApplication({
}: {
dependencyStore: DependencyStore;
}): Promise<HealthcheckApplication> {
const taskScheduling =
dependencyStore.retrieve<TaskScheduling>("taskScheduling");
const cache = dependencyStore.retrieve<Cache>("cache");
const { healthcheck: healthcheckRepository } =
dependencyStore.retrieve<Repository>("repository");
const taskScheduling = dependencyStore.get("taskScheduling");

const enqueueSomeTask = await taskScheduling.createTask<{ id: string }>(
"someTask",
Expand All @@ -35,10 +25,7 @@ export async function createHealthcheckApplication({

return {
async getHealthcheck() {
return getHealthcheck({
cache,
healthcheckRepository,
});
return getHealthcheck({ dependencyStore });
},
};
}
30 changes: 14 additions & 16 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type {
import {
createCacheStorage,
createDatabase,
createDependencyStore,
createDateProvider,
createHttpServer,
createLoggerProvider,
createShutdownManager,
Expand All @@ -25,18 +25,16 @@ import { config } from "~/config.js";
import { createAppRouter } from "~/presentation/http/index.js";
import { createRepository } from "~/repository/index.js";

import { dateProvider } from "./infrastructure/date";
import { dependencyStore } from "./store";

export async function startApp() {
const dependencyStore = createDependencyStore();

const createLogger = createLoggerProvider({ config });
dependencyStore.provide("logger", createLogger);
const logger = createLogger("app");

const telemetry = createTelemetry({ config, dependencyStore });
dependencyStore.provide("telemetry", telemetry);
dependencyStore.set("logger", createLogger);

const logger = createLogger("app");
const telemetry = createTelemetry({ config, dependencyStore });
dependencyStore.set("telemetry", telemetry);

const appStartedTimestamp = Date.now();
logger.info(`starting service ${config.name}...`, {
Expand All @@ -46,7 +44,7 @@ export async function startApp() {
platform: process.platform,
});

dependencyStore.provide("date", dateProvider);
dependencyStore.set("date", createDateProvider());

let database: Database;
let cache: Cache;
Expand All @@ -57,21 +55,21 @@ export async function startApp() {

try {
cache = await createCacheStorage({ config, dependencyStore });
dependencyStore.provide("cache", cache);
dependencyStore.set("cache", cache);

taskScheduling = createTaskScheduling({ config, dependencyStore });
dependencyStore.provide("taskScheduling", taskScheduling);
dependencyStore.set("taskScheduling", taskScheduling);

database = await createDatabase({ config, dependencyStore });
dependencyStore.provide("database", database);
dependencyStore.set("database", database);

const repository = createRepository({ database });
dependencyStore.provide("repository", repository);
const repository = createRepository({ dependencyStore });
dependencyStore.set("repository", repository);

const healthcheckApplication = await createHealthcheckApplication({
dependencyStore,
});
dependencyStore.provide("healthcheckApplication", healthcheckApplication);
dependencyStore.set("healthcheckApplication", healthcheckApplication);

const appRouter = createAppRouter({ dependencyStore });

Expand All @@ -80,7 +78,7 @@ export async function startApp() {
dependencyStore,
appRouter,
});
dependencyStore.provide("httpServer", httpServer);
dependencyStore.set("httpServer", httpServer);

shutdown = createShutdownManager({
config,
Expand Down
9 changes: 0 additions & 9 deletions src/infrastructure/date.ts

This file was deleted.

8 changes: 2 additions & 6 deletions src/presentation/http/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { DependencyStore } from "@gjuchault/typescript-service-sdk";
import { initContract } from "@ts-rest/core";
import { initServer } from "@ts-rest/fastify";

import type { HealthcheckApplication } from "~/application/healthcheck/index.js";
import { DependencyStore } from "~/store.js";

import {
bindHealthcheckRoutes,
Expand All @@ -25,11 +24,8 @@ export function createAppRouter({
}: {
dependencyStore: DependencyStore;
}) {
const healthcheckApplication =
dependencyStore.retrieve<HealthcheckApplication>("healthcheckApplication");

const healthcheckRouter = bindHealthcheckRoutes({
healthcheckApplication,
dependencyStore,
});

return s.router(contract, {
Expand Down
Loading

0 comments on commit 4125e56

Please sign in to comment.