Skip to content

Commit 41f671e

Browse files
authored
Merge pull request #637 from devforth/next
Next
2 parents 8c860a8 + fc4d1ed commit 41f671e

33 files changed

Lines changed: 897 additions & 369 deletions

adminforth/dataConnectors/baseConnector.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
4444
return this.client;
4545
}
4646

47-
setupClient(url: string): Promise<void> {
47+
setupClient(url: string, options?: { recovery?: boolean }): Promise<void> {
4848
throw new Error('Method not implemented.');
4949
}
5050

adminforth/dataConnectors/postgres.ts

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,35 @@ types.setTypeParser(1082, (val) => val); // DATE
1616

1717
class PostgresConnector extends AdminForthBaseConnector implements IAdminForthDataSourceConnector {
1818

19-
async setupClient(url: string): Promise<void> {
19+
async setupClient(url: string, options?: { recovery?: boolean }): Promise<void> {
2020
this.client = new Pool({
2121
connectionString: url
2222
});
23-
try {
24-
await this.client.connect();
25-
this.client.on('error', async (err) => {
26-
afLogger.error(`Postgres error: ${err.message} ${err.stack}`);
27-
this.client.end();
28-
await new Promise((resolve) => { setTimeout(resolve, 1000) });
29-
this.setupClient(url);
23+
24+
const selfHeal = options?.recovery !== false;
25+
26+
if (selfHeal) {
27+
this.client.on('error', (err) => {
28+
afLogger.error(`Postgres pool idle client error (pool self-heals on next query): ${err.message} ${err.stack}`);
3029
});
31-
} catch (e) {
32-
afLogger.error(`Failed to connect to Postgres ${e}`);
30+
try {
31+
const client = await this.client.connect();
32+
client.release();
33+
} catch (e) {
34+
afLogger.error(`Failed to connect to Postgres ${e}`);
35+
}
36+
} else {
37+
try {
38+
await this.client.connect();
39+
this.client.on('error', async (err) => {
40+
afLogger.error(`Postgres error: ${err.message} ${err.stack}`);
41+
this.client.end();
42+
await new Promise((resolve) => { setTimeout(resolve, 1000) });
43+
this.setupClient(url, options);
44+
});
45+
} catch (e) {
46+
afLogger.error(`Failed to connect to Postgres ${e}`);
47+
}
3348
}
3449
}
3550

adminforth/documentation/docs/tutorial/02-glossary.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,25 @@ It used to:
1515

1616
There might be several datasources in the system for various databases e.g. One datasource to Mongo DBs and one to Postgres DB.
1717

18+
### connectionRecovery
19+
20+
For PostgreSQL datasources AdminForth keeps a connection pool. The optional `connectionRecovery` flag controls how the connector reacts when that connection drops (DB restart, failover, network blip, etc.):
21+
22+
```ts
23+
dataSources: [
24+
{
25+
id: 'maindb',
26+
url: `${process.env.DATABASE_URL}`,
27+
connectionRecovery: true, // default
28+
},
29+
],
30+
```
31+
32+
- `true` (default, recommended) — **self-heal mode.** The pool recovers automatically: a dead idle connection is dropped and a fresh one is transparently opened on the next query, so the app keeps working without a manual restart. Queries that were in-flight at the moment of the outage will fail, but subsequent queries succeed once the database is back.
33+
- `false`**legacy mode.** On a connection error the pool is destroyed and recreated after 1 second. If the outage outlasts that retry, the app can be left with a permanently dead pool and require a manual restart. Kept only for backward compatibility.
34+
35+
This flag is currently honored by the PostgreSQL connector; other connectors rely on their driver's built-in recovery.
36+
1837
## resource
1938

2039
A [Resource](/docs/api/Back/interfaces/AdminForthResource.md) is a AdminForth representation of a table or collection in database. One resource is one table in the database. Resource has `table` property which should be equal to the name of the table in the database.

0 commit comments

Comments
 (0)