Skip to content

Commit

Permalink
Added guide on gracefuly stopping PostgreSQL connection
Browse files Browse the repository at this point in the history
  • Loading branch information
oskardudycz committed Jan 26, 2025
1 parent 76d7c3e commit 4c84364
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 19 deletions.
22 changes: 14 additions & 8 deletions src/docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,13 +146,13 @@ It brings you three most important methods:
- `appendToStream` - appends new events at the end of the stream. All events should be appended as an atomic operation. You can specify the expected stream version for an [optimistic concurrency check](https://event-driven.io/en/optimistic_concurrency_for_pessimistic_times/). We're also getting the next stream version as a result.
- `aggregateStream` - builds the current state from events. Internally, event store implementation should read all events in the stream based on the passed initial state and the `evolve` function. It also supports all the same options as the `readStream` method.

Emmett provides you with out-of-the-box support for the following storage:
**Emmett provides you with out-of-the-box support for the following storage:**

- PostgreSQL with [emmett-postgresql](https://www.npmjs.com/package/@event-driven-io/emmett-postgresql) package,
- EventStoreDB with [emmett-esdb](https://www.npmjs.com/package/@event-driven-io/emmett-esdb) package,
- MongoDB with [emmett-mongodb](https://www.npmjs.com/package/@event-driven-io/emmett-mongodb) package,
- SQLite with [emmett-sqlite](https://www.npmjs.com/package/@event-driven-io/emmett-sqlite) package,
- In-Memory with regular [emmett](https://www.npmjs.com/package/@event-driven-io/emmett) package.
- **PostgreSQL** with [emmett-postgresql](https://www.npmjs.com/package/@event-driven-io/emmett-postgresql) package,
- **EventStoreDB** with [emmett-esdb](https://www.npmjs.com/package/@event-driven-io/emmett-esdb) package,
- **MongoDB** with [emmett-mongodb](https://www.npmjs.com/package/@event-driven-io/emmett-mongodb) package,
- **SQLite** with [emmett-sqlite](https://www.npmjs.com/package/@event-driven-io/emmett-sqlite) package,
- **In-Memory** with regular [emmett](https://www.npmjs.com/package/@event-driven-io/emmett) package.

Read more about how event stores are built in the [article](https://event-driven.io/en/lets_build_event_store_in_one_hour/).

Expand Down Expand Up @@ -456,8 +456,6 @@ $ yarn add @testcontainers/postgresql
$ bun add @testcontainers/postgresql
```

:::

::: info EventStoreDB testing

Emmett provides the package with additional test containers like the one for [EventStoreDB](https://developers.eventstore.com/). If you're using EventStoreDB, install [emmett-testcontainers](https://www.npmjs.com/package/@event-driven-io/emmett-testcontainers) and get the test container for it.
Expand All @@ -468,6 +466,14 @@ Having that, we can set our test container with:

<<< @/snippets/gettingStarted/webApi/apiBDDE2EGiven.ts#test-container

::: info Event store lifetime

The PostgreSQL event store creates an internal connection pool to use PostgreSQL efficiently. **Because of that, we recommend using a single event store instance per application.** The same advice applies to other storages.

After the application ends or tests are finished, we need to close it to gracefully release open connections in the connection pool.

:::

And create our test specification using the `ApiE2ESpecification` type:

<<< @/snippets/gettingStarted/webApi/apiBDDE2EGiven.ts#given
Expand Down
14 changes: 11 additions & 3 deletions src/docs/snippets/gettingStarted/webApi/apiBDD.e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ import {
getApplication,
type TestRequest,
} from '@event-driven-io/emmett-expressjs';
import { getPostgreSQLEventStore } from '@event-driven-io/emmett-postgresql';
import {
getPostgreSQLEventStore,
type PostgresEventStore,
} from '@event-driven-io/emmett-postgresql';
import {
PostgreSqlContainer,
type StartedPostgreSqlContainer,
Expand All @@ -22,13 +25,17 @@ void describe('ShoppingCart E2E', () => {
let clientId: string;
let shoppingCartId: string;
let postgreSQLContainer: StartedPostgreSqlContainer;
let eventStore: PostgresEventStore;
let given: ApiE2ESpecification;

before(async () => {
postgreSQLContainer = await new PostgreSqlContainer().start();
eventStore = getPostgreSQLEventStore(
postgreSQLContainer.getConnectionUri(),
);

given = ApiE2ESpecification.for(
() => getPostgreSQLEventStore(postgreSQLContainer.getConnectionUri()),
() => eventStore,
(eventStore) =>
getApplication({
apis: [
Expand All @@ -47,7 +54,8 @@ void describe('ShoppingCart E2E', () => {
shoppingCartId = `shopping_cart:${clientId}:current`;
});

after(() => {
after(async () => {
await eventStore.close();
return postgreSQLContainer.stop();
});

Expand Down
22 changes: 16 additions & 6 deletions src/docs/snippets/gettingStarted/webApi/apiBDDE2EGiven.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,45 @@ const unitPrice = 100;
const now = new Date();

// #region test-container
import {
getPostgreSQLEventStore,
type PostgresEventStore,
} from '@event-driven-io/emmett-postgresql';
import {
PostgreSqlContainer,
StartedPostgreSqlContainer,
} from '@testcontainers/postgresql';

let postgreSQLContainer: StartedPostgreSqlContainer;
void describe('ShoppingCart E2E', () => {
// Set up a container before all tests
let postgreSQLContainer: StartedPostgreSqlContainer;
let eventStore: PostgresEventStore;

// Set up a container and event store before all tests
before(async () => {
postgreSQLContainer = await new PostgreSqlContainer().start();
eventStore = getPostgreSQLEventStore(
postgreSQLContainer.getConnectionUri(),
);
});

// Stop container once we finished testing
after(() => {
// Close PostgreSQL connection and stop container once we finished testing
after(async () => {
await eventStore.close();
return postgreSQLContainer.stop();
});
// (...) Tests will go here
});
// #endregion test-container

const eventStore: PostgresEventStore = undefined!;
// #region given
import {
ApiE2ESpecification,
getApplication,
} from '@event-driven-io/emmett-expressjs';
import { getPostgreSQLEventStore } from '@event-driven-io/emmett-postgresql';

const given = ApiE2ESpecification.for(
() => getPostgreSQLEventStore(postgreSQLContainer.getConnectionUri()),
() => eventStore,
(eventStore) =>
getApplication({
apis: [
Expand Down
4 changes: 2 additions & 2 deletions src/docs/snippets/gettingStarted/webApi/apiBDDE2ETest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {
getApplication,
type TestRequest,
} from '@event-driven-io/emmett-expressjs';
import { getPostgreSQLEventStore } from '@event-driven-io/emmett-postgresql';
import type { StartedPostgreSqlContainer } from '@testcontainers/postgresql';
import { randomUUID } from 'node:crypto';
import { describe, it } from 'node:test';
import type { PricedProductItem } from '../events';
Expand Down Expand Up @@ -39,8 +41,6 @@ const productItem = getRandomProduct();

// #region test
import { expectResponse } from '@event-driven-io/emmett-expressjs';
import { getPostgreSQLEventStore } from '@event-driven-io/emmett-postgresql';
import type { StartedPostgreSqlContainer } from '@testcontainers/postgresql';

void describe('When opened with product item', () => {
const openedShoppingCartWithProduct: TestRequest = (request) =>
Expand Down

0 comments on commit 4c84364

Please sign in to comment.