@backstage/plugin-catalog-backend-module-incremental-ingestion 0.2.0-next.0 → 0.2.0-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/README.md +114 -93
- package/alpha/package.json +1 -1
- package/dist/index.alpha.d.ts +2 -1
- package/dist/index.beta.d.ts +2 -1
- package/dist/index.cjs.js +19 -12
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/package.json +12 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
# @backstage/plugin-catalog-backend-module-incremental-ingestion
|
|
2
2
|
|
|
3
|
+
## 0.2.0-next.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 407dc01fc9: Removing extra imports for `run` script as `TestBackend` auto loads the default factories
|
|
8
|
+
- 77c41b6924: Updated README to include newer API options for incremental entity providers
|
|
9
|
+
- Updated dependencies
|
|
10
|
+
- @backstage/backend-plugin-api@0.4.0-next.2
|
|
11
|
+
- @backstage/backend-test-utils@0.1.34-next.2
|
|
12
|
+
- @backstage/backend-common@0.18.2-next.2
|
|
13
|
+
- @backstage/plugin-catalog-backend@1.7.2-next.2
|
|
14
|
+
- @backstage/catalog-model@1.2.0-next.1
|
|
15
|
+
- @backstage/plugin-events-node@0.2.3-next.2
|
|
16
|
+
- @backstage/plugin-catalog-node@1.3.3-next.2
|
|
17
|
+
- @backstage/backend-tasks@0.4.3-next.2
|
|
18
|
+
- @backstage/config@1.0.6
|
|
19
|
+
- @backstage/errors@1.1.4
|
|
20
|
+
- @backstage/plugin-permission-common@0.7.3
|
|
21
|
+
|
|
22
|
+
## 0.2.0-next.1
|
|
23
|
+
|
|
24
|
+
### Patch Changes
|
|
25
|
+
|
|
26
|
+
- b7e36660d5: Return `EventSubscriber` from `addIncrementalEntityProvider` to hook up to `EventsBackend`
|
|
27
|
+
- Updated dependencies
|
|
28
|
+
- @backstage/plugin-catalog-backend@1.7.2-next.1
|
|
29
|
+
- @backstage/backend-common@0.18.2-next.1
|
|
30
|
+
- @backstage/backend-plugin-api@0.3.2-next.1
|
|
31
|
+
- @backstage/backend-tasks@0.4.3-next.1
|
|
32
|
+
- @backstage/backend-test-utils@0.1.34-next.1
|
|
33
|
+
- @backstage/catalog-model@1.1.6-next.0
|
|
34
|
+
- @backstage/config@1.0.6
|
|
35
|
+
- @backstage/errors@1.1.4
|
|
36
|
+
- @backstage/plugin-catalog-node@1.3.3-next.1
|
|
37
|
+
- @backstage/plugin-events-node@0.2.3-next.1
|
|
38
|
+
- @backstage/plugin-permission-common@0.7.3
|
|
39
|
+
|
|
3
40
|
## 0.2.0-next.0
|
|
4
41
|
|
|
5
42
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ The Incremental Ingestion catalog backend module provides an Incremental Entity
|
|
|
4
4
|
|
|
5
5
|
## Why did we create it?
|
|
6
6
|
|
|
7
|
-
Backstage provides an [Entity Provider mechanism that has two kinds of mutations](https://backstage.io/docs/features/software-catalog/external-integrations#provider-mutations): `delta` and `full`. `delta` mutations tell Backstage Catalog which entities should be added and removed from the catalog. `full`
|
|
7
|
+
Backstage provides an [Entity Provider mechanism that has two kinds of mutations](https://backstage.io/docs/features/software-catalog/external-integrations#provider-mutations): `delta` and `full`. `delta` mutations tell the Backstage Catalog which entities should be added and removed from the catalog. `full` mutations accept a list of entities and automatically computes which entities must be removed by comparing the provided entities against existing entities to create a diff between the two sets. These two kinds of mutations are convenient for different kinds of data sources. A `delta` mutation can be used with a data source that emits UPDATE and DELETE events for its data. A `full` mutation is useful for APIs that produce fewer entities than can fit in the Backstage processes' memory.
|
|
8
8
|
|
|
9
9
|
Unfortunately, these two kinds of mutations are insufficient for very large data sources for the following reasons,
|
|
10
10
|
|
|
@@ -42,68 +42,80 @@ The Incremental Entity Provider backend is designed for data sources that provid
|
|
|
42
42
|
## Installation
|
|
43
43
|
|
|
44
44
|
1. Install `@backstage/plugin-catalog-backend-module-incremental-ingestion` with `yarn workspace backend add @backstage/plugin-catalog-backend-module-incremental-ingestion`
|
|
45
|
-
2.
|
|
45
|
+
2. In your catalog.ts, import `IncrementalCatalogBuilder` from `@backstage/plugin-catalog-backend-module-incremental-ingestion` and instantiate it with `await IncrementalCatalogBuilder.create(env, builder)`. You have to pass `builder` into `IncrementalCatalogBuilder.create` function because `IncrementalCatalogBuilder` will convert an `IncrementalEntityProvider` into an `EntityProvider` and call `builder.addEntityProvider`.
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
builder,
|
|
54
|
-
);
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
3. Last step, add `await incrementBuilder.build()` after `await builder.build()` to ensure that all `CatalogBuilder` migration run before running `incrementBuilder.build()` migrations.
|
|
58
|
-
|
|
59
|
-
```ts
|
|
60
|
-
const { processingEngine, router } = await builder.build();
|
|
61
|
-
|
|
62
|
-
// this has to run after `await builder.build()` to ensure that catalog migrations are completed
|
|
63
|
-
// before incremental builder migrations are executed
|
|
64
|
-
await incrementalBuilder.build();
|
|
65
|
-
```
|
|
47
|
+
```ts
|
|
48
|
+
const builder = CatalogBuilder.create(env);
|
|
49
|
+
// incremental builder receives builder because it'll register
|
|
50
|
+
// incremental entity providers with the builder
|
|
51
|
+
const incrementalBuilder = await IncrementalCatalogBuilder.create(env, builder);
|
|
52
|
+
```
|
|
66
53
|
|
|
67
|
-
|
|
54
|
+
3. After building the regular `CatalogBuilder`, build the incremental builder:
|
|
68
55
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
import { IncrementalCatalogBuilder } from '@backstage/plugin-catalog-backend-module-incremental-ingestion';
|
|
73
|
-
import { Router } from 'express';
|
|
74
|
-
import { Duration } from 'luxon';
|
|
75
|
-
import { PluginEnvironment } from '../types';
|
|
56
|
+
```ts
|
|
57
|
+
// Must be run first to ensure CatalogBuilder database migrations run before Incremental Entity Provider database migrations
|
|
58
|
+
const { processingEngine, router } = await builder.build();
|
|
76
59
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const builder = CatalogBuilder.create(env);
|
|
81
|
-
// incremental builder receives builder because it'll register
|
|
82
|
-
// incremental entity providers with the builder
|
|
83
|
-
const incrementalBuilder = await IncrementalCatalogBuilder.create(
|
|
84
|
-
env,
|
|
85
|
-
builder,
|
|
86
|
-
);
|
|
60
|
+
// Returns an optional - but highly recommended - set of administrative routes
|
|
61
|
+
const { incrementalAdminRouter } = await incrementBuilder.build();
|
|
62
|
+
```
|
|
87
63
|
|
|
88
|
-
|
|
64
|
+
The final result should look something like this,
|
|
89
65
|
|
|
90
|
-
|
|
66
|
+
```ts
|
|
67
|
+
import { CatalogBuilder } from '@backstage/plugin-catalog-backend';
|
|
68
|
+
import { ScaffolderEntitiesProcessor } from '@backstage/plugin-scaffolder-backend';
|
|
69
|
+
import { IncrementalCatalogBuilder } from '@backstage/plugin-catalog-backend-module-incremental-ingestion';
|
|
70
|
+
import { Router } from 'express';
|
|
71
|
+
import { Duration } from 'luxon';
|
|
72
|
+
import { PluginEnvironment } from '../types';
|
|
73
|
+
|
|
74
|
+
export default async function createPlugin(
|
|
75
|
+
env: PluginEnvironment,
|
|
76
|
+
): Promise<Router> {
|
|
77
|
+
const builder = CatalogBuilder.create(env);
|
|
78
|
+
// incremental builder receives builder because it'll register
|
|
79
|
+
// incremental entity providers with the builder
|
|
80
|
+
const incrementalBuilder = await IncrementalCatalogBuilder.create(
|
|
81
|
+
env,
|
|
82
|
+
builder,
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
builder.addProcessor(new ScaffolderEntitiesProcessor());
|
|
86
|
+
|
|
87
|
+
const { processingEngine, router } = await builder.build();
|
|
88
|
+
const { incrementalAdminRouter } = await incrementalBuilder.build();
|
|
89
|
+
|
|
90
|
+
router.use(incrementalAdminRouter);
|
|
91
|
+
|
|
92
|
+
await processingEngine.start();
|
|
93
|
+
|
|
94
|
+
return router;
|
|
95
|
+
}
|
|
96
|
+
```
|
|
91
97
|
|
|
92
|
-
|
|
93
|
-
// before incremental builder migrations are executed
|
|
94
|
-
const { incrementalAdminRouter } = await incrementalBuilder.build();
|
|
98
|
+
## Administrative Routes
|
|
95
99
|
|
|
96
|
-
|
|
100
|
+
If you want to manage your incremental entity providers via REST endpoints, the following endpoints are available:
|
|
97
101
|
|
|
98
|
-
|
|
102
|
+
| Method | Path | Description |
|
|
103
|
+
| ------ | ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------- |
|
|
104
|
+
| GET | `/incremental/health` | Checks the health of all incremental providers. Returns array of any unhealthy ones. |
|
|
105
|
+
| GET | `/incremental/providers/:provider` | Checks the status of an incremental provider (resting, interstitial, etc). |
|
|
106
|
+
| POST | `/incremental/providers/:provider/trigger` | Triggers a provider's next action immediately. E.g., if it's currently interstitial, it will trigger the next burst. |
|
|
107
|
+
| POST | `/incremental/providers/:provider/start` | Stop the current ingestion cycle and start a new one immediately. |
|
|
108
|
+
| POST | `/incremental/providers/:provider/cancel` | Stop the current ingestion cycle and start a new one in 24 hours. |
|
|
109
|
+
| DELETE | `/incremental/providers/:provider` | Completely remove all records for the provider and schedule it to start again in 24 hours. |
|
|
110
|
+
| GET | `/incremental/providers/:provider/marks` | Retrieve a list of all ingestion marks for the current ingestion cycle. |
|
|
111
|
+
| DELETE | `/incremental/providers/:provider/marks` | Remove all ingestion marks for the current ingestion cycle. |
|
|
112
|
+
| POST | `/incremental/cleanup` | Completely remove all records for ALL providers and schedule them to start again in 24 hours. (CAUTION! Can cause orphans!) |
|
|
99
113
|
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
```
|
|
114
|
+
In all cases, `:provider` is the name of the incremental entity provider.
|
|
103
115
|
|
|
104
116
|
## Writing an Incremental Entity Provider
|
|
105
117
|
|
|
106
|
-
To create an Incremental Entity Provider, you need to know how to retrieve a single page of the data that you wish to ingest into the Backstage catalog. If the API has pagination and you know how to make a paginated request to that API, you'll be able to implement an Incremental Entity Provider for this API. For more information about compatibility,
|
|
118
|
+
To create an Incremental Entity Provider, you need to know how to retrieve a single page of the data that you wish to ingest into the Backstage catalog. If the API has pagination and you know how to make a paginated request to that API, you'll be able to implement an Incremental Entity Provider for this API. For more information about compatibility, check out the <a href="#requirements">requirements</a> section of this page.
|
|
107
119
|
|
|
108
120
|
Here is the type definition for an Incremental Entity Provider.
|
|
109
121
|
|
|
@@ -114,33 +126,31 @@ interface IncrementalEntityProvider<TCursor, TContext> {
|
|
|
114
126
|
* operating in the catalog.
|
|
115
127
|
*/
|
|
116
128
|
getProviderName(): string;
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Do any setup and teardown necessary in order to provide the
|
|
120
|
-
* context for fetching pages. This should always invoke `burst` in
|
|
121
|
-
* order to fetch the individual pages.
|
|
122
|
-
*
|
|
123
|
-
* @param burst - a function which performs a series of iterations
|
|
124
|
-
*/
|
|
125
|
-
around(burst: (context: TContext) => Promise<void>): Promise<void>;
|
|
126
|
-
|
|
127
129
|
/**
|
|
128
130
|
* Return a single page of entities from a specific point in the
|
|
129
131
|
* ingestion.
|
|
130
132
|
*
|
|
131
133
|
* @param context - anything needed in order to fetch a single page.
|
|
132
134
|
* @param cursor - a unique value identifying the page to ingest.
|
|
133
|
-
* @returns
|
|
134
|
-
* the
|
|
135
|
+
* @returns The entities to be ingested, as well as the cursor of
|
|
136
|
+
* the next page after this one.
|
|
135
137
|
*/
|
|
136
138
|
next(
|
|
137
139
|
context: TContext,
|
|
138
140
|
cursor?: TCursor,
|
|
139
141
|
): Promise<EntityIteratorResult<TCursor>>;
|
|
142
|
+
/**
|
|
143
|
+
* Do any setup and teardown necessary in order to provide the
|
|
144
|
+
* context for fetching pages. This should always invoke `burst` in
|
|
145
|
+
* order to fetch the individual pages.
|
|
146
|
+
*
|
|
147
|
+
* @param burst - a function which performs a series of iterations
|
|
148
|
+
*/
|
|
149
|
+
around(burst: (context: TContext) => Promise<void>): Promise<void>;
|
|
140
150
|
}
|
|
141
151
|
```
|
|
142
152
|
|
|
143
|
-
For tutorial, we'll write an Incremental Entity Provider that will call an imaginary API. This imaginary API will return a list of imaginary services.
|
|
153
|
+
For this tutorial, we'll write an Incremental Entity Provider that will call an imaginary API. This imaginary API will return a list of imaginary services. The imaginary API has an imaginary API client with the following interface.
|
|
144
154
|
|
|
145
155
|
```ts
|
|
146
156
|
interface MyApiClient {
|
|
@@ -157,15 +167,12 @@ interface Service {
|
|
|
157
167
|
}
|
|
158
168
|
```
|
|
159
169
|
|
|
160
|
-
These are the only 3 methods that you need to implement. `getProviderName()` is pretty self explanatory and it's
|
|
170
|
+
These are the only 3 methods that you need to implement. `getProviderName()` is pretty self explanatory and it's identical to the `getProviderName()` method on a regular Entity Provider.
|
|
161
171
|
|
|
162
172
|
```ts
|
|
163
|
-
import {
|
|
164
|
-
IncrementalEntityProvider,
|
|
165
|
-
EntityIteratorResult,
|
|
166
|
-
} from '@backstage/plugin-catalog-backend-module-incremental-ingestion';
|
|
173
|
+
import { IncrementalEntityProvider } from '@backstage/plugin-catalog-backend-module-incremental-ingestion';
|
|
167
174
|
|
|
168
|
-
//
|
|
175
|
+
// This will include your pagination information, let's say our API accepts a `page` parameter.
|
|
169
176
|
// In this case, the cursor will include `page`
|
|
170
177
|
interface MyApiCursor {
|
|
171
178
|
page: number;
|
|
@@ -200,7 +207,7 @@ export class MyIncrementalEntityProvider
|
|
|
200
207
|
|
|
201
208
|
await burst({ apiClient });
|
|
202
209
|
|
|
203
|
-
//
|
|
210
|
+
// If you need to do any teardown, you can do it here.
|
|
204
211
|
}
|
|
205
212
|
}
|
|
206
213
|
```
|
|
@@ -306,31 +313,45 @@ We'll assume you followed the <a href="#installation">Installation</a> instructi
|
|
|
306
313
|
```ts
|
|
307
314
|
const incrementalBuilder = await IncrementalCatalogBuilder.create(env, builder);
|
|
308
315
|
|
|
309
|
-
//
|
|
316
|
+
// Assuming the token for the API comes from config
|
|
310
317
|
const token = config.getString('myApiClient.token');
|
|
311
318
|
|
|
312
|
-
const myEntityProvider = new MyIncrementalEntityProvider(token)
|
|
313
|
-
|
|
314
|
-
incrementalBuilder.addIncrementalEntityProvider(
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
319
|
+
const myEntityProvider = new MyIncrementalEntityProvider(token);
|
|
320
|
+
|
|
321
|
+
incrementalBuilder.addIncrementalEntityProvider(myEntityProvider, {
|
|
322
|
+
// How long should it attempt to read pages from the API in a
|
|
323
|
+
// single burst? Keep this short. The Incremental Entity Provider
|
|
324
|
+
// will attempt to read as many pages as it can in this time
|
|
325
|
+
burstLength: Duration.fromObject({ seconds: 3 }),
|
|
326
|
+
|
|
327
|
+
// How long should it wait between bursts?
|
|
328
|
+
burstInterval: Duration.fromObject({ seconds: 3 }),
|
|
329
|
+
|
|
330
|
+
// How long should it rest before re-ingesting again?
|
|
331
|
+
restLength: Duration.fromObject({ day: 1 }),
|
|
332
|
+
|
|
333
|
+
// Optional back-off configuration - how long should it wait to retry
|
|
334
|
+
// in the event of an error?
|
|
335
|
+
backoff: [
|
|
336
|
+
Duration.fromObject({ seconds: 5 }),
|
|
337
|
+
Duration.fromObject({ seconds: 30 }),
|
|
338
|
+
Duration.fromObject({ minutes: 10 }),
|
|
339
|
+
Duration.fromObject({ hours: 3 }),
|
|
340
|
+
],
|
|
341
|
+
|
|
342
|
+
// Optional. Use this to prevent removal of entities above a given
|
|
343
|
+
// percentage. This can be helpful if a data source is flaky and
|
|
344
|
+
// sometimes returns a successful status, but fewer than expected
|
|
345
|
+
// assets to add or maintain in the catalog.
|
|
346
|
+
rejectRemovalsAbovePercentage: 5,
|
|
347
|
+
|
|
348
|
+
// Optional. Similar to rejectRemovalsAbovePercentage, except it
|
|
349
|
+
// applies to complete, 100% failure of a data source. If true,
|
|
350
|
+
// a data source that returns a successful status but does not
|
|
351
|
+
// provide any assets to turn into entities will have its empty
|
|
352
|
+
// data set rejected.
|
|
353
|
+
rejectEmptySourceCollections: true,
|
|
354
|
+
});
|
|
334
355
|
```
|
|
335
356
|
|
|
336
357
|
That's it!!!
|
package/alpha/package.json
CHANGED
package/dist/index.alpha.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type { Config } from '@backstage/config';
|
|
|
12
12
|
import type { DeferredEntity } from '@backstage/plugin-catalog-backend';
|
|
13
13
|
import type { DurationObjectUnits } from 'luxon';
|
|
14
14
|
import { EventParams } from '@backstage/plugin-events-node';
|
|
15
|
+
import { EventSubscriber } from '@backstage/plugin-events-node';
|
|
15
16
|
import type { Logger } from 'winston';
|
|
16
17
|
import type { PermissionEvaluator } from '@backstage/plugin-permission-common';
|
|
17
18
|
import type { PluginDatabaseManager } from '@backstage/backend-common';
|
|
@@ -53,7 +54,7 @@ export declare class IncrementalCatalogBuilder {
|
|
|
53
54
|
build(): Promise<{
|
|
54
55
|
incrementalAdminRouter: Router;
|
|
55
56
|
}>;
|
|
56
|
-
addIncrementalEntityProvider<TCursor, TContext>(provider: IncrementalEntityProvider<TCursor, TContext>, options: IncrementalEntityProviderOptions):
|
|
57
|
+
addIncrementalEntityProvider<TCursor, TContext>(provider: IncrementalEntityProvider<TCursor, TContext>, options: IncrementalEntityProviderOptions): EventSubscriber;
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
/**
|
package/dist/index.beta.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type { Config } from '@backstage/config';
|
|
|
12
12
|
import type { DeferredEntity } from '@backstage/plugin-catalog-backend';
|
|
13
13
|
import type { DurationObjectUnits } from 'luxon';
|
|
14
14
|
import { EventParams } from '@backstage/plugin-events-node';
|
|
15
|
+
import { EventSubscriber } from '@backstage/plugin-events-node';
|
|
15
16
|
import type { Logger } from 'winston';
|
|
16
17
|
import type { PermissionEvaluator } from '@backstage/plugin-permission-common';
|
|
17
18
|
import type { PluginDatabaseManager } from '@backstage/backend-common';
|
|
@@ -53,7 +54,7 @@ export declare class IncrementalCatalogBuilder {
|
|
|
53
54
|
build(): Promise<{
|
|
54
55
|
incrementalAdminRouter: Router;
|
|
55
56
|
}>;
|
|
56
|
-
addIncrementalEntityProvider<TCursor, TContext>(provider: IncrementalEntityProvider<TCursor, TContext>, options: IncrementalEntityProviderOptions):
|
|
57
|
+
addIncrementalEntityProvider<TCursor, TContext>(provider: IncrementalEntityProvider<TCursor, TContext>, options: IncrementalEntityProviderOptions): EventSubscriber;
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
/**
|
package/dist/index.cjs.js
CHANGED
|
@@ -163,14 +163,14 @@ class IncrementalIngestionDatabaseManager {
|
|
|
163
163
|
ingestionIDs.map((entry) => entry.id)
|
|
164
164
|
) : 0;
|
|
165
165
|
const ingestionsDeleted = await tx("ingestions").delete().where("provider_name", provider);
|
|
166
|
-
const next_action_at = new Date();
|
|
166
|
+
const next_action_at = /* @__PURE__ */ new Date();
|
|
167
167
|
next_action_at.setTime(next_action_at.getTime() + 24 * 60 * 60 * 1e3);
|
|
168
168
|
await this.insertIngestionRecord({
|
|
169
169
|
id: uuid.v4(),
|
|
170
170
|
next_action: "rest",
|
|
171
171
|
provider_name: provider,
|
|
172
172
|
next_action_at,
|
|
173
|
-
ingestion_completed_at: new Date(),
|
|
173
|
+
ingestion_completed_at: /* @__PURE__ */ new Date(),
|
|
174
174
|
status: "resting",
|
|
175
175
|
completion_ticket: "open"
|
|
176
176
|
});
|
|
@@ -257,7 +257,7 @@ class IncrementalIngestionDatabaseManager {
|
|
|
257
257
|
*/
|
|
258
258
|
async triggerNextProviderAction(provider) {
|
|
259
259
|
await this.updateIngestionRecordByProvider(provider, {
|
|
260
|
-
next_action_at: new Date()
|
|
260
|
+
next_action_at: /* @__PURE__ */ new Date()
|
|
261
261
|
});
|
|
262
262
|
}
|
|
263
263
|
/**
|
|
@@ -272,7 +272,7 @@ class IncrementalIngestionDatabaseManager {
|
|
|
272
272
|
async cleanupProviders() {
|
|
273
273
|
const providers = await this.listProviders();
|
|
274
274
|
const ingestionsDeleted = await this.purgeTable("ingestions");
|
|
275
|
-
const next_action_at = new Date();
|
|
275
|
+
const next_action_at = /* @__PURE__ */ new Date();
|
|
276
276
|
next_action_at.setTime(next_action_at.getTime() + 24 * 60 * 60 * 1e3);
|
|
277
277
|
for (const provider of providers) {
|
|
278
278
|
await this.insertIngestionRecord({
|
|
@@ -280,7 +280,7 @@ class IncrementalIngestionDatabaseManager {
|
|
|
280
280
|
next_action: "rest",
|
|
281
281
|
provider_name: provider,
|
|
282
282
|
next_action_at,
|
|
283
|
-
ingestion_completed_at: new Date(),
|
|
283
|
+
ingestion_completed_at: /* @__PURE__ */ new Date(),
|
|
284
284
|
status: "resting",
|
|
285
285
|
completion_ticket: "open"
|
|
286
286
|
});
|
|
@@ -320,7 +320,7 @@ class IncrementalIngestionDatabaseManager {
|
|
|
320
320
|
ingestionId,
|
|
321
321
|
update: {
|
|
322
322
|
next_action: "nothing (done)",
|
|
323
|
-
rest_completed_at: new Date(),
|
|
323
|
+
rest_completed_at: /* @__PURE__ */ new Date(),
|
|
324
324
|
status: "complete",
|
|
325
325
|
completion_ticket: uuid.v4()
|
|
326
326
|
}
|
|
@@ -337,7 +337,7 @@ class IncrementalIngestionDatabaseManager {
|
|
|
337
337
|
update: {
|
|
338
338
|
next_action: "rest",
|
|
339
339
|
next_action_at: new Date(Date.now() + restLength.as("milliseconds")),
|
|
340
|
-
ingestion_completed_at: new Date(),
|
|
340
|
+
ingestion_completed_at: /* @__PURE__ */ new Date(),
|
|
341
341
|
status: "resting"
|
|
342
342
|
}
|
|
343
343
|
});
|
|
@@ -361,7 +361,7 @@ class IncrementalIngestionDatabaseManager {
|
|
|
361
361
|
const update = {
|
|
362
362
|
next_action: "cancel",
|
|
363
363
|
last_error: message ? message : void 0,
|
|
364
|
-
next_action_at: new Date(),
|
|
364
|
+
next_action_at: /* @__PURE__ */ new Date(),
|
|
365
365
|
status: "canceling"
|
|
366
366
|
};
|
|
367
367
|
await this.updateIngestionRecordById({ ingestionId, update });
|
|
@@ -375,7 +375,7 @@ class IncrementalIngestionDatabaseManager {
|
|
|
375
375
|
ingestionId,
|
|
376
376
|
update: {
|
|
377
377
|
next_action: "nothing (canceled)",
|
|
378
|
-
rest_completed_at: new Date(),
|
|
378
|
+
rest_completed_at: /* @__PURE__ */ new Date(),
|
|
379
379
|
status: "complete",
|
|
380
380
|
completion_ticket: uuid.v4()
|
|
381
381
|
}
|
|
@@ -939,11 +939,11 @@ class IncrementalProviderRouter {
|
|
|
939
939
|
const { provider } = req.params;
|
|
940
940
|
const record = await this.manager.getCurrentIngestionRecord(provider);
|
|
941
941
|
if (record) {
|
|
942
|
-
const next_action_at = new Date();
|
|
942
|
+
const next_action_at = /* @__PURE__ */ new Date();
|
|
943
943
|
next_action_at.setTime(next_action_at.getTime() + 24 * 60 * 60 * 1e3);
|
|
944
944
|
await this.manager.updateByName(provider, {
|
|
945
945
|
next_action: "nothing (done)",
|
|
946
|
-
ingestion_completed_at: new Date(),
|
|
946
|
+
ingestion_completed_at: /* @__PURE__ */ new Date(),
|
|
947
947
|
next_action_at,
|
|
948
948
|
status: "resting"
|
|
949
949
|
});
|
|
@@ -1205,6 +1205,7 @@ class IncrementalCatalogBuilder {
|
|
|
1205
1205
|
const { logger: catalogLogger, scheduler } = this.env;
|
|
1206
1206
|
const ready = this.ready;
|
|
1207
1207
|
const manager = this.manager;
|
|
1208
|
+
let engine;
|
|
1208
1209
|
this.builder.addEntityProvider({
|
|
1209
1210
|
getProviderName: provider.getProviderName.bind(provider),
|
|
1210
1211
|
async connect(connection) {
|
|
@@ -1212,7 +1213,7 @@ class IncrementalCatalogBuilder {
|
|
|
1212
1213
|
entityProvider: provider.getProviderName()
|
|
1213
1214
|
});
|
|
1214
1215
|
logger.info(`Connecting`);
|
|
1215
|
-
|
|
1216
|
+
engine = new IncrementalIngestionEngine({
|
|
1216
1217
|
...options,
|
|
1217
1218
|
ready,
|
|
1218
1219
|
manager,
|
|
@@ -1231,6 +1232,12 @@ class IncrementalCatalogBuilder {
|
|
|
1231
1232
|
});
|
|
1232
1233
|
}
|
|
1233
1234
|
});
|
|
1235
|
+
return {
|
|
1236
|
+
onEvent: (params) => engine.onEvent(params),
|
|
1237
|
+
supportsEventTopics() {
|
|
1238
|
+
return engine.supportsEventTopics();
|
|
1239
|
+
}
|
|
1240
|
+
};
|
|
1234
1241
|
}
|
|
1235
1242
|
}
|
|
1236
1243
|
|
package/dist/index.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":["../src/database/IncrementalIngestionDatabaseManager.ts","../src/database/tables.ts","../src/database/migrations.ts","../src/engine/IncrementalIngestionEngine.ts","../src/router/paths.ts","../src/router/routes.ts","../src/util.ts","../src/module/WrapperProviders.ts","../src/module/incrementalIngestionEntityProviderCatalogModule.ts","../src/service/IncrementalCatalogBuilder.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Knex } from 'knex';\nimport type { DeferredEntity } from '@backstage/plugin-catalog-backend';\nimport { stringifyEntityRef } from '@backstage/catalog-model';\nimport { Duration } from 'luxon';\nimport { v4 } from 'uuid';\nimport {\n IngestionRecord,\n IngestionRecordUpdate,\n IngestionUpsert,\n MarkRecord,\n MarkRecordInsert,\n} from './tables';\n\nexport class IncrementalIngestionDatabaseManager {\n private client: Knex;\n\n constructor(options: { client: Knex }) {\n this.client = options.client;\n }\n\n /**\n * Performs an update to the ingestion record with matching `id`.\n * @param options - IngestionRecordUpdate\n */\n async updateIngestionRecordById(options: IngestionRecordUpdate) {\n await this.client.transaction(async tx => {\n const { ingestionId, update } = options;\n await tx('ingestions').where('id', ingestionId).update(update);\n });\n }\n\n /**\n * Performs an update to the ingestion record with matching provider name. Will only update active records.\n * @param provider - string\n * @param update - Partial<IngestionUpsertIFace>\n */\n async updateIngestionRecordByProvider(\n provider: string,\n update: Partial<IngestionUpsert>,\n ) {\n await this.client.transaction(async tx => {\n await tx('ingestions')\n .where('provider_name', provider)\n .andWhere('completion_ticket', 'open')\n .update(update);\n });\n }\n\n /**\n * Performs an insert into the `ingestions` table with the supplied values.\n * @param record - IngestionUpsertIFace\n */\n async insertIngestionRecord(record: IngestionUpsert) {\n await this.client.transaction(async tx => {\n await tx('ingestions').insert(record);\n });\n }\n\n private async deleteMarkEntities(\n tx: Knex.Transaction,\n ids: { id: string }[],\n ) {\n const chunks: { id: string }[][] = [];\n for (let i = 0; i < ids.length; i += 100) {\n const chunk = ids.slice(i, i + 100);\n chunks.push(chunk);\n }\n\n let deleted = 0;\n\n for (const chunk of chunks) {\n const chunkDeleted = await tx('ingestion_mark_entities')\n .delete()\n .whereIn(\n 'id',\n chunk.map(entry => entry.id),\n );\n deleted += chunkDeleted;\n }\n\n return deleted;\n }\n\n /**\n * Finds the current ingestion record for the named provider.\n * @param provider - string\n * @returns IngestionRecord | undefined\n */\n async getCurrentIngestionRecord(provider: string) {\n return await this.client.transaction(async tx => {\n const record = await tx<IngestionRecord>('ingestions')\n .where('provider_name', provider)\n .andWhere('completion_ticket', 'open')\n .first();\n return record;\n });\n }\n\n /**\n * Finds the last ingestion record for the named provider.\n * @param provider - string\n * @returns IngestionRecord | undefined\n */\n async getPreviousIngestionRecord(provider: string) {\n return await this.client.transaction(async tx => {\n return await tx<IngestionRecord>('ingestions')\n .where('provider_name', provider)\n .andWhereNot('completion_ticket', 'open')\n .first();\n });\n }\n\n /**\n * Removes all entries from `ingestion_marks_entities`, `ingestion_marks`, and `ingestions`\n * for prior ingestions that completed (i.e., have a `completion_ticket` value other than 'open').\n * @param provider - string\n * @returns A count of deletions for each record type.\n */\n async clearFinishedIngestions(provider: string) {\n return await this.client.transaction(async tx => {\n const markEntitiesDeleted = await tx('ingestion_mark_entities')\n .delete()\n .whereIn(\n 'ingestion_mark_id',\n tx('ingestion_marks')\n .select('id')\n .whereIn(\n 'ingestion_id',\n tx('ingestions')\n .select('id')\n .where('provider_name', provider)\n .andWhereNot('completion_ticket', 'open'),\n ),\n );\n\n const marksDeleted = await tx('ingestion_marks')\n .delete()\n .whereIn(\n 'ingestion_id',\n tx('ingestions')\n .select('id')\n .where('provider_name', provider)\n .andWhereNot('completion_ticket', 'open'),\n );\n\n const ingestionsDeleted = await tx('ingestions')\n .delete()\n .where('provider_name', provider)\n .andWhereNot('completion_ticket', 'open');\n\n return {\n deletions: {\n markEntitiesDeleted,\n marksDeleted,\n ingestionsDeleted,\n },\n };\n });\n }\n\n /**\n * Automatically cleans up duplicate ingestion records if they were accidentally created.\n * Any ingestion record where the `rest_completed_at` is null (meaning it is active) AND\n * the ingestionId is incorrect is a duplicate ingestion record.\n * @param ingestionId - string\n * @param provider - string\n */\n async clearDuplicateIngestions(ingestionId: string, provider: string) {\n await this.client.transaction(async tx => {\n const invalid = await tx<IngestionRecord>('ingestions')\n .where('provider_name', provider)\n .andWhere('rest_completed_at', null)\n .andWhereNot('id', ingestionId);\n\n if (invalid.length > 0) {\n await tx('ingestions').delete().whereIn('id', invalid);\n await tx('ingestion_mark_entities')\n .delete()\n .whereIn(\n 'ingestion_mark_id',\n tx('ingestion_marks').select('id').whereIn('ingestion_id', invalid),\n );\n await tx('ingestion_marks').delete().whereIn('ingestion_id', invalid);\n }\n });\n }\n\n /**\n * This method fully purges and resets all ingestion records for the named provider, and\n * leaves it in a paused state.\n * @param provider - string\n * @returns Counts of all deleted ingestion records\n */\n async purgeAndResetProvider(provider: string) {\n return await this.client.transaction(async tx => {\n const ingestionIDs: { id: string }[] = await tx('ingestions')\n .select('id')\n .where('provider_name', provider);\n\n const markIDs: { id: string }[] =\n ingestionIDs.length > 0\n ? await tx('ingestion_marks')\n .select('id')\n .whereIn(\n 'ingestion_id',\n ingestionIDs.map(entry => entry.id),\n )\n : [];\n\n const markEntityIDs: { id: string }[] =\n markIDs.length > 0\n ? await tx('ingestion_mark_entities')\n .select('id')\n .whereIn(\n 'ingestion_mark_id',\n markIDs.map(entry => entry.id),\n )\n : [];\n\n const markEntitiesDeleted = await this.deleteMarkEntities(\n tx,\n markEntityIDs,\n );\n\n const marksDeleted =\n markIDs.length > 0\n ? await tx('ingestion_marks')\n .delete()\n .whereIn(\n 'ingestion_id',\n ingestionIDs.map(entry => entry.id),\n )\n : 0;\n\n const ingestionsDeleted = await tx('ingestions')\n .delete()\n .where('provider_name', provider);\n\n const next_action_at = new Date();\n next_action_at.setTime(next_action_at.getTime() + 24 * 60 * 60 * 1000);\n\n await this.insertIngestionRecord({\n id: v4(),\n next_action: 'rest',\n provider_name: provider,\n next_action_at,\n ingestion_completed_at: new Date(),\n status: 'resting',\n completion_ticket: 'open',\n });\n\n return { provider, ingestionsDeleted, marksDeleted, markEntitiesDeleted };\n });\n }\n\n /**\n * This method is used to remove entity records from the ingestion_mark_entities\n * table by their entity reference.\n */\n async deleteEntityRecordsByRef(entities: { entityRef: string }[]) {\n const refs = entities.map(e => e.entityRef);\n await this.client.transaction(async tx => {\n await tx('ingestion_mark_entities').delete().whereIn('ref', refs);\n });\n }\n\n /**\n * Creates a new ingestion record.\n * @param provider - string\n * @returns A new ingestion record\n */\n async createProviderIngestionRecord(provider: string) {\n const ingestionId = v4();\n const nextAction = 'ingest';\n try {\n await this.insertIngestionRecord({\n id: ingestionId,\n next_action: nextAction,\n provider_name: provider,\n status: 'bursting',\n completion_ticket: 'open',\n });\n return { ingestionId, nextAction, attempts: 0, nextActionAt: Date.now() };\n } catch (_e) {\n // Creating the ingestion record failed. Return undefined.\n return undefined;\n }\n }\n\n /**\n * Computes which entities to remove, if any, at the end of a burst.\n * @param provider - string\n * @param ingestionId - string\n * @returns All entities to remove for this burst.\n */\n async computeRemoved(provider: string, ingestionId: string) {\n const previousIngestion = await this.getPreviousIngestionRecord(provider);\n return await this.client.transaction(async tx => {\n const count = await tx('ingestion_mark_entities')\n .count({ total: 'ingestion_mark_entities.ref' })\n .join(\n 'ingestion_marks',\n 'ingestion_marks.id',\n 'ingestion_mark_entities.ingestion_mark_id',\n )\n .join('ingestions', 'ingestions.id', 'ingestion_marks.ingestion_id')\n .where('ingestions.id', ingestionId);\n\n const total = count.reduce((acc, cur) => acc + (cur.total as number), 0);\n\n const removed: { entityRef: string }[] = [];\n if (previousIngestion) {\n const stale: { ref: string }[] = await tx('ingestion_mark_entities')\n .select('ingestion_mark_entities.ref')\n .join(\n 'ingestion_marks',\n 'ingestion_marks.id',\n 'ingestion_mark_entities.ingestion_mark_id',\n )\n .join('ingestions', 'ingestions.id', 'ingestion_marks.ingestion_id')\n .where('ingestions.id', previousIngestion.id);\n\n removed.push(\n ...stale.map(e => {\n return { entityRef: e.ref };\n }),\n );\n }\n\n return { total, removed };\n });\n }\n\n /**\n * Performs a lookup of all providers that have duplicate active ingestion records.\n * @returns An array of all duplicate active ingestions\n */\n async healthcheck() {\n return await this.client.transaction(async tx => {\n const records = await tx<{ id: string; provider_name: string }>(\n 'ingestions',\n )\n .distinct('id', 'provider_name')\n .where('rest_completed_at', null);\n return records;\n });\n }\n\n /**\n * Skips any wait time for the next action to run.\n * @param provider - string\n */\n async triggerNextProviderAction(provider: string) {\n await this.updateIngestionRecordByProvider(provider, {\n next_action_at: new Date(),\n });\n }\n\n /**\n * Purges the following tables:\n * * `ingestions`\n * * `ingestion_marks`\n * * `ingestion_mark_entities`\n *\n * This function leaves the ingestions table with all providers in a paused state.\n * @returns Results from cleaning up all ingestion tables.\n */\n async cleanupProviders() {\n const providers = await this.listProviders();\n\n const ingestionsDeleted = await this.purgeTable('ingestions');\n\n const next_action_at = new Date();\n next_action_at.setTime(next_action_at.getTime() + 24 * 60 * 60 * 1000);\n\n for (const provider of providers) {\n await this.insertIngestionRecord({\n id: v4(),\n next_action: 'rest',\n provider_name: provider,\n next_action_at,\n ingestion_completed_at: new Date(),\n status: 'resting',\n completion_ticket: 'open',\n });\n }\n\n const ingestionMarksDeleted = await this.purgeTable('ingestion_marks');\n const markEntitiesDeleted = await this.purgeTable(\n 'ingestion_mark_entities',\n );\n\n return { ingestionsDeleted, ingestionMarksDeleted, markEntitiesDeleted };\n }\n\n /**\n * Configures the current ingestion record to ingest a burst.\n * @param ingestionId - string\n */\n async setProviderIngesting(ingestionId: string) {\n await this.updateIngestionRecordById({\n ingestionId,\n update: { next_action: 'ingest' },\n });\n }\n\n /**\n * Indicates the provider is currently ingesting a burst.\n * @param ingestionId - string\n */\n async setProviderBursting(ingestionId: string) {\n await this.updateIngestionRecordById({\n ingestionId,\n update: { status: 'bursting' },\n });\n }\n\n /**\n * Finalizes the current ingestion record to indicate that the post-ingestion rest period is complete.\n * @param ingestionId - string\n */\n async setProviderComplete(ingestionId: string) {\n await this.updateIngestionRecordById({\n ingestionId,\n update: {\n next_action: 'nothing (done)',\n rest_completed_at: new Date(),\n status: 'complete',\n completion_ticket: v4(),\n },\n });\n }\n\n /**\n * Marks ingestion as complete and starts the post-ingestion rest cycle.\n * @param ingestionId - string\n * @param restLength - Duration\n */\n async setProviderResting(ingestionId: string, restLength: Duration) {\n await this.updateIngestionRecordById({\n ingestionId,\n update: {\n next_action: 'rest',\n next_action_at: new Date(Date.now() + restLength.as('milliseconds')),\n ingestion_completed_at: new Date(),\n status: 'resting',\n },\n });\n }\n\n /**\n * Marks ingestion as paused after a burst completes.\n * @param ingestionId - string\n */\n async setProviderInterstitial(ingestionId: string) {\n await this.updateIngestionRecordById({\n ingestionId,\n update: { attempts: 0, status: 'interstitial' },\n });\n }\n\n /**\n * Starts the cancel process for the current ingestion.\n * @param ingestionId - string\n * @param message - string (optional)\n */\n async setProviderCanceling(ingestionId: string, message?: string) {\n const update: Partial<IngestionUpsert> = {\n next_action: 'cancel',\n last_error: message ? message : undefined,\n next_action_at: new Date(),\n status: 'canceling',\n };\n await this.updateIngestionRecordById({ ingestionId, update });\n }\n\n /**\n * Completes the cancel process and triggers a new ingestion.\n * @param ingestionId - string\n */\n async setProviderCanceled(ingestionId: string) {\n await this.updateIngestionRecordById({\n ingestionId,\n update: {\n next_action: 'nothing (canceled)',\n rest_completed_at: new Date(),\n status: 'complete',\n completion_ticket: v4(),\n },\n });\n }\n\n /**\n * Configures the current ingestion to wait and retry, due to a data source error.\n * @param ingestionId - string\n * @param attempts - number\n * @param error - Error\n * @param backoffLength - number\n */\n async setProviderBackoff(\n ingestionId: string,\n attempts: number,\n error: Error,\n backoffLength: number,\n ) {\n await this.updateIngestionRecordById({\n ingestionId,\n update: {\n next_action: 'backoff',\n attempts: attempts + 1,\n last_error: String(error),\n next_action_at: new Date(Date.now() + backoffLength),\n status: 'backing off',\n },\n });\n }\n\n /**\n * Returns the last record from `ingestion_marks` for the supplied ingestionId.\n * @param ingestionId - string\n * @returns MarkRecord | undefined\n */\n async getLastMark(ingestionId: string) {\n return await this.client.transaction(async tx => {\n const mark = await tx<MarkRecord>('ingestion_marks')\n .where('ingestion_id', ingestionId)\n .orderBy('sequence', 'desc')\n .first();\n return mark;\n });\n }\n\n /**\n * Returns the first record from `ingestion_marks` for the supplied ingestionId.\n * @param ingestionId - string\n * @returns MarkRecord | undefined\n */\n async getFirstMark(ingestionId: string) {\n return await this.client.transaction(async tx => {\n const mark = await tx<MarkRecord>('ingestion_marks')\n .where('ingestion_id', ingestionId)\n .orderBy('sequence', 'asc')\n .first();\n return mark;\n });\n }\n\n async getAllMarks(ingestionId: string) {\n return await this.client.transaction(async tx => {\n const marks = await tx<MarkRecord>('ingestion_marks')\n .where('ingestion_id', ingestionId)\n .orderBy('sequence', 'desc');\n return marks;\n });\n }\n\n /**\n * Performs an insert into the `ingestion_marks` table with the supplied values.\n * @param options - MarkRecordInsert\n */\n async createMark(options: MarkRecordInsert) {\n const { record } = options;\n await this.client.transaction(async tx => {\n await tx('ingestion_marks').insert(record);\n });\n }\n /**\n * Performs an upsert to the `ingestion_mark_entities` table for all deferred entities.\n * @param markId - string\n * @param entities - DeferredEntity[]\n */\n async createMarkEntities(markId: string, entities: DeferredEntity[]) {\n const refs = entities.map(e => stringifyEntityRef(e.entity));\n\n await this.client.transaction(async tx => {\n const existingRefsArray = (\n await tx<{ ref: string }>('ingestion_mark_entities')\n .select('ref')\n .whereIn('ref', refs)\n ).map(e => e.ref);\n\n const existingRefsSet = new Set(existingRefsArray);\n\n const newRefs = refs.filter(e => !existingRefsSet.has(e));\n\n await tx('ingestion_mark_entities')\n .update('ingestion_mark_id', markId)\n .whereIn('ref', existingRefsArray);\n\n if (newRefs.length > 0) {\n await tx('ingestion_mark_entities').insert(\n newRefs.map(ref => ({\n id: v4(),\n ingestion_mark_id: markId,\n ref,\n })),\n );\n }\n });\n }\n\n /**\n * Deletes the entire content of a table, and returns the number of records deleted.\n * @param table - string\n * @returns number\n */\n async purgeTable(table: string) {\n return await this.client.transaction(async tx => {\n return await tx(table).delete();\n });\n }\n\n /**\n * Returns a list of all providers.\n * @returns string[]\n */\n async listProviders() {\n return await this.client.transaction(async tx => {\n const providers = await tx<{ provider_name: string }>(\n 'ingestions',\n ).distinct('provider_name');\n return providers.map(entry => entry.provider_name);\n });\n }\n\n async updateByName(provider: string, update: Partial<IngestionUpsert>) {\n await this.updateIngestionRecordByProvider(provider, update);\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport const DB_MIGRATIONS_TABLE = 'incremental_ingestion__knex_migrations';\n\n/**\n * The shape of data inserted into or updated in the `ingestions` table.\n */\nexport interface IngestionUpsert {\n /**\n * The ingestion record id.\n */\n id?: string;\n /**\n * The next action the incremental entity provider will take.\n */\n next_action:\n | 'rest'\n | 'ingest'\n | 'backoff'\n | 'cancel'\n | 'nothing (done)'\n | 'nothing (canceled)';\n /**\n * Current status of the incremental entity provider.\n */\n status:\n | 'complete'\n | 'bursting'\n | 'resting'\n | 'canceling'\n | 'interstitial'\n | 'backing off';\n /**\n * The name of the incremental entity provider being updated.\n */\n provider_name: string;\n /**\n * Date/time stamp for when the next action will trigger.\n */\n next_action_at?: Date;\n /**\n * A record of the last error generated by the incremental entity provider.\n */\n last_error?: string | null;\n /**\n * The number of attempts the provider has attempted during the current cycle.\n */\n attempts?: number;\n /**\n * Date/time stamp for the completion of ingestion.\n */\n ingestion_completed_at?: Date | string | null;\n /**\n * Date/time stamp for the end of the rest cycle before the next ingestion.\n */\n rest_completed_at?: Date | string | null;\n /**\n * A record of the finalized status of the ingestion record. Values are either 'open' or a uuid.\n */\n completion_ticket: string;\n}\n\n/**\n * This interface is for updating an existing ingestion record.\n */\nexport interface IngestionRecordUpdate {\n ingestionId: string;\n update: Partial<IngestionUpsert>;\n}\n\n/**\n * The expected response from the `ingestion_marks` table.\n */\nexport interface MarkRecord {\n id: string;\n sequence: number;\n ingestion_id: string;\n cursor: string;\n created_at: string;\n}\n\n/**\n * The expected response from the `ingestions` table.\n */\nexport interface IngestionRecord extends IngestionUpsert {\n id: string;\n next_action_at: Date;\n /**\n * The date/time the ingestion record was created.\n */\n created_at: string;\n}\n\n/**\n * This interface supplies all the values for adding an ingestion mark.\n */\nexport interface MarkRecordInsert {\n record: {\n id: string;\n ingestion_id: string;\n cursor: unknown;\n sequence: number;\n };\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { resolvePackagePath } from '@backstage/backend-common';\nimport { Knex } from 'knex';\nimport { DB_MIGRATIONS_TABLE } from './tables';\n\nexport async function applyDatabaseMigrations(knex: Knex): Promise<void> {\n const migrationsDir = resolvePackagePath(\n '@backstage/plugin-catalog-backend-module-incremental-ingestion',\n 'migrations',\n );\n\n await knex.migrate.latest({\n directory: migrationsDir,\n tableName: DB_MIGRATIONS_TABLE,\n });\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { DeferredEntity } from '@backstage/plugin-catalog-backend';\nimport { IterationEngine, IterationEngineOptions } from '../types';\nimport { IncrementalIngestionDatabaseManager } from '../database/IncrementalIngestionDatabaseManager';\nimport { performance } from 'perf_hooks';\nimport { Duration, DurationObjectUnits } from 'luxon';\nimport { v4 } from 'uuid';\nimport { stringifyError } from '@backstage/errors';\nimport { EventParams, EventSubscriber } from '@backstage/plugin-events-node';\n\nexport class IncrementalIngestionEngine\n implements IterationEngine, EventSubscriber\n{\n private readonly restLength: Duration;\n private readonly backoff: DurationObjectUnits[];\n\n private manager: IncrementalIngestionDatabaseManager;\n\n constructor(private options: IterationEngineOptions) {\n this.manager = options.manager;\n this.restLength = Duration.fromObject(options.restLength);\n this.backoff = options.backoff ?? [\n { minutes: 1 },\n { minutes: 5 },\n { minutes: 30 },\n { hours: 3 },\n ];\n }\n\n async taskFn(signal: AbortSignal) {\n try {\n this.options.logger.debug('Begin tick');\n await this.handleNextAction(signal);\n } catch (error) {\n this.options.logger.error(`${error}`);\n throw error;\n } finally {\n this.options.logger.debug('End tick');\n }\n }\n\n async handleNextAction(signal: AbortSignal) {\n await this.options.ready;\n\n const result = await this.getCurrentAction();\n if (result) {\n const { ingestionId, nextActionAt, nextAction, attempts } = result;\n\n switch (nextAction) {\n case 'rest':\n if (Date.now() > nextActionAt) {\n await this.manager.clearFinishedIngestions(\n this.options.provider.getProviderName(),\n );\n this.options.logger.info(\n `incremental-engine: Ingestion ${ingestionId} rest period complete. Ingestion will start again`,\n );\n\n await this.manager.setProviderComplete(ingestionId);\n } else {\n this.options.logger.info(\n `incremental-engine: Ingestion '${ingestionId}' rest period continuing`,\n );\n }\n break;\n case 'ingest':\n try {\n await this.manager.setProviderBursting(ingestionId);\n const done = await this.ingestOneBurst(ingestionId, signal);\n if (done) {\n this.options.logger.info(\n `incremental-engine: Ingestion '${ingestionId}' complete, transitioning to rest period of ${this.restLength.toHuman()}`,\n );\n await this.manager.setProviderResting(\n ingestionId,\n this.restLength,\n );\n } else {\n await this.manager.setProviderInterstitial(ingestionId);\n this.options.logger.info(\n `incremental-engine: Ingestion '${ingestionId}' continuing`,\n );\n }\n } catch (error) {\n if (\n (error as Error).message &&\n (error as Error).message === 'CANCEL'\n ) {\n this.options.logger.info(\n `incremental-engine: Ingestion '${ingestionId}' canceled`,\n );\n await this.manager.setProviderCanceling(\n ingestionId,\n (error as Error).message,\n );\n } else {\n const currentBackoff = Duration.fromObject(\n this.backoff[Math.min(this.backoff.length - 1, attempts)],\n );\n\n const backoffLength = currentBackoff.as('milliseconds');\n this.options.logger.error(\n `incremental-engine: Ingestion '${ingestionId}' failed`,\n error,\n );\n\n const truncatedError = stringifyError(error).substring(0, 700);\n this.options.logger.error(\n `incremental-engine: Ingestion '${ingestionId}' threw an error during ingestion burst. Ingestion will backoff for ${currentBackoff.toHuman()} (${truncatedError})`,\n );\n\n await this.manager.setProviderBackoff(\n ingestionId,\n attempts,\n error as Error,\n backoffLength,\n );\n }\n }\n break;\n case 'backoff':\n if (Date.now() > nextActionAt) {\n this.options.logger.info(\n `incremental-engine: Ingestion '${ingestionId}' backoff complete, will attempt to resume`,\n );\n await this.manager.setProviderIngesting(ingestionId);\n } else {\n this.options.logger.info(\n `incremental-engine: Ingestion '${ingestionId}' backoff continuing`,\n );\n }\n break;\n case 'cancel':\n this.options.logger.info(\n `incremental-engine: Ingestion '${ingestionId}' canceling, will restart`,\n );\n await this.manager.setProviderCanceled(ingestionId);\n break;\n default:\n this.options.logger.error(\n `incremental-engine: Ingestion '${ingestionId}' received unknown action '${nextAction}'`,\n );\n }\n } else {\n this.options.logger.error(\n `incremental-engine: Engine tried to create duplicate ingestion record for provider '${this.options.provider.getProviderName()}'.`,\n );\n }\n }\n\n async getCurrentAction() {\n const providerName = this.options.provider.getProviderName();\n const record = await this.manager.getCurrentIngestionRecord(providerName);\n if (record) {\n this.options.logger.info(\n `incremental-engine: Ingestion record found: '${record.id}'`,\n );\n return {\n ingestionId: record.id,\n nextAction: record.next_action as 'rest' | 'ingest' | 'backoff',\n attempts: record.attempts as number,\n nextActionAt: record.next_action_at.valueOf() as number,\n };\n }\n const result = await this.manager.createProviderIngestionRecord(\n providerName,\n );\n if (result) {\n this.options.logger.info(\n `incremental-engine: Ingestion record created: '${result.ingestionId}'`,\n );\n }\n return result;\n }\n\n async ingestOneBurst(id: string, signal: AbortSignal) {\n const lastMark = await this.manager.getLastMark(id);\n\n const cursor = lastMark ? lastMark.cursor : undefined;\n let sequence = lastMark ? lastMark.sequence + 1 : 0;\n\n const start = performance.now();\n let count = 0;\n let done = false;\n this.options.logger.info(\n `incremental-engine: Ingestion '${id}' burst initiated`,\n );\n\n await this.options.provider.around(async (context: unknown) => {\n let next = await this.options.provider.next(context, cursor);\n count++;\n for (;;) {\n done = next.done;\n await this.mark({\n id,\n sequence,\n entities: next?.entities,\n done: next.done,\n cursor: next?.cursor,\n });\n if (signal.aborted || next.done) {\n break;\n } else {\n next = await this.options.provider.next(context, next.cursor);\n count++;\n sequence++;\n }\n }\n });\n\n this.options.logger.info(\n `incremental-engine: Ingestion '${id}' burst complete. (${count} batches in ${Math.round(\n performance.now() - start,\n )}ms).`,\n );\n return done;\n }\n\n async mark(options: {\n id: string;\n sequence: number;\n entities?: DeferredEntity[];\n done: boolean;\n cursor?: unknown;\n }) {\n const { id, sequence, entities, done, cursor } = options;\n this.options.logger.debug(\n `incremental-engine: Ingestion '${id}': MARK ${\n entities ? entities.length : 0\n } entities, cursor: ${\n cursor ? JSON.stringify(cursor) : 'none'\n }, done: ${done}`,\n );\n const markId = v4();\n\n await this.manager.createMark({\n record: {\n id: markId,\n ingestion_id: id,\n cursor,\n sequence,\n },\n });\n\n if (entities && entities.length > 0) {\n await this.manager.createMarkEntities(markId, entities);\n }\n\n const added =\n entities?.map(deferred => ({\n ...deferred,\n entity: {\n ...deferred.entity,\n metadata: {\n ...deferred.entity.metadata,\n annotations: {\n ...deferred.entity.metadata.annotations,\n },\n },\n },\n })) ?? [];\n\n const removed: { entityRef: string }[] = [];\n\n if (done) {\n this.options.logger.info(\n `incremental-engine: Ingestion '${id}': Final page reached, calculating removed entities`,\n );\n const result = await this.manager.computeRemoved(\n this.options.provider.getProviderName(),\n id,\n );\n\n const { total } = result;\n\n let doRemoval = true;\n if (this.options.rejectEmptySourceCollections) {\n if (total === 0) {\n this.options.logger.error(\n `incremental-engine: Ingestion '${id}': Rejecting empty entity collection!`,\n );\n doRemoval = false;\n }\n }\n\n if (this.options.rejectRemovalsAbovePercentage) {\n // If the total entities upserted in this ingestion is 0, then\n // 100% of entities are stale and marked for removal.\n const percentRemoved =\n total > 0 ? (result.removed.length / total) * 100 : 100;\n if (percentRemoved <= this.options.rejectRemovalsAbovePercentage) {\n this.options.logger.info(\n `incremental-engine: Ingestion '${id}': Removing ${result.removed.length} entities that have no matching assets`,\n );\n } else {\n const notice = `Attempted to remove ${percentRemoved}% of matching entities!`;\n this.options.logger.error(\n `incremental-engine: Ingestion '${id}': ${notice}`,\n );\n await this.manager.updateIngestionRecordById({\n ingestionId: id,\n update: {\n last_error: `REMOVAL_THRESHOLD exceeded on ingestion mark ${markId}: ${notice}`,\n },\n });\n doRemoval = false;\n }\n }\n if (doRemoval) {\n removed.push(...result.removed);\n }\n }\n\n await this.options.connection.applyMutation({\n type: 'delta',\n added,\n removed,\n });\n }\n\n async onEvent(params: EventParams): Promise<void> {\n const { topic } = params;\n if (!this.supportsEventTopics().includes(topic)) {\n return;\n }\n\n const { logger, provider, connection } = this.options;\n const providerName = provider.getProviderName();\n logger.debug(`incremental-engine: ${providerName} received ${topic} event`);\n\n if (!provider.eventHandler) {\n return;\n }\n\n const delta = provider.eventHandler.onEvent(params);\n\n if (delta) {\n if (delta.added.length > 0) {\n const ingestionRecord = await this.manager.getCurrentIngestionRecord(\n providerName,\n );\n\n if (!ingestionRecord) {\n logger.debug(\n `incremental-engine: ${providerName} skipping delta addition because incremental ingestion is restarting.`,\n );\n } else {\n const mark =\n ingestionRecord.status === 'resting'\n ? await this.manager.getLastMark(ingestionRecord.id)\n : await this.manager.getFirstMark(ingestionRecord.id);\n\n if (!mark) {\n throw new Error(\n `Cannot apply delta, page records are missing! Please re-run incremental ingestion for ${providerName}.`,\n );\n }\n await this.manager.createMarkEntities(mark.id, delta.added);\n }\n }\n\n if (delta.removed.length > 0) {\n await this.manager.deleteEntityRecordsByRef(delta.removed);\n }\n\n await connection.applyMutation({\n type: 'delta',\n ...delta,\n });\n logger.debug(\n `incremental-engine: ${providerName} processed delta from '${topic}' event`,\n );\n } else {\n logger.warn(\n `incremental-engine: Rejected delta from '${topic}' event - empty or invalid`,\n );\n }\n }\n\n supportsEventTopics(): string[] {\n const { provider } = this.options;\n const topics = provider.eventHandler\n ? provider.eventHandler.supportsEventTopics()\n : [];\n return topics;\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport const PROVIDER_CLEANUP = '/incremental/cleanup';\nexport const PROVIDER_HEALTH = '/incremental/health';\nexport const PROVIDER_BASE_PATH = '/incremental/providers/:provider';\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { errorHandler } from '@backstage/backend-common';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { Logger } from 'winston';\nimport { IncrementalIngestionDatabaseManager } from '../database/IncrementalIngestionDatabaseManager';\nimport { PROVIDER_BASE_PATH, PROVIDER_CLEANUP, PROVIDER_HEALTH } from './paths';\n\nexport class IncrementalProviderRouter {\n private manager: IncrementalIngestionDatabaseManager;\n private logger: Logger;\n\n constructor(manager: IncrementalIngestionDatabaseManager, logger: Logger) {\n this.manager = manager;\n this.logger = logger;\n }\n\n async createRouter() {\n const router = Router();\n router.use(express.json());\n\n // Get the overall health of all incremental providers\n router.get(PROVIDER_HEALTH, async (_, res) => {\n const records = await this.manager.healthcheck();\n const providers = records.map(record => record.provider_name);\n const duplicates = [\n ...new Set(providers.filter((e, i, a) => a.indexOf(e) !== i)),\n ];\n\n if (duplicates.length > 0) {\n res.json({ healthy: false, duplicateIngestions: duplicates });\n } else {\n res.json({ healthy: true });\n }\n });\n\n // Clean up and pause all providers\n router.post(PROVIDER_CLEANUP, async (_, res) => {\n const result = await this.manager.cleanupProviders();\n res.json(result);\n });\n\n // Get basic status of the provider\n router.get(PROVIDER_BASE_PATH, async (req, res) => {\n const { provider } = req.params;\n const record = await this.manager.getCurrentIngestionRecord(provider);\n if (record) {\n res.json({\n success: true,\n status: {\n current_action: record.status,\n next_action_at: new Date(record.next_action_at),\n },\n last_error: record.last_error,\n });\n } else {\n const providers: string[] = await this.manager.listProviders();\n if (providers.includes(provider)) {\n res.json({\n success: true,\n status: {\n current_action: 'rest complete, waiting to start',\n },\n });\n } else {\n this.logger.error(\n `${provider} - No ingestion record found in the database!`,\n );\n res.status(404).json({\n success: false,\n status: {},\n last_error: `Provider '${provider}' not found`,\n });\n }\n }\n });\n\n // Trigger the provider's next action\n router.post(`${PROVIDER_BASE_PATH}/trigger`, async (req, res) => {\n const { provider } = req.params;\n const record = await this.manager.getCurrentIngestionRecord(provider);\n if (record) {\n await this.manager.triggerNextProviderAction(provider);\n res.json({\n success: true,\n message: `${provider}: Next action triggered.`,\n });\n } else {\n const providers: string[] = await this.manager.listProviders();\n if (providers.includes(provider)) {\n this.logger.debug(`${provider} - Ingestion record found`);\n res.json({\n success: true,\n message: 'Unable to trigger next action (provider is restarting)',\n });\n } else {\n res.status(404).json({\n success: false,\n message: `Provider '${provider}' not found`,\n });\n }\n }\n });\n\n // Start a brand-new ingestion cycle for the provider.\n // (Cancel's the current run if active, or marks it complete if resting)\n router.post(`${PROVIDER_BASE_PATH}/start`, async (req, res) => {\n const { provider } = req.params;\n\n const record = await this.manager.getCurrentIngestionRecord(provider);\n if (record) {\n const ingestionId = record.id;\n if (record.status === 'resting') {\n await this.manager.setProviderComplete(ingestionId);\n } else {\n await this.manager.setProviderCanceling(ingestionId);\n }\n res.json({\n success: true,\n message: `${provider}: Next cycle triggered.`,\n });\n } else {\n const providers: string[] = await this.manager.listProviders();\n if (providers.includes(provider)) {\n this.logger.debug(`${provider} - Ingestion record found`);\n res.json({\n success: true,\n message: 'Provider is already restarting',\n });\n } else {\n res.status(404).json({\n success: false,\n message: `Provider '${provider}' not found`,\n });\n }\n }\n });\n\n // Stop the provider and pause it for 24 hours\n router.post(`${PROVIDER_BASE_PATH}/cancel`, async (req, res) => {\n const { provider } = req.params;\n const record = await this.manager.getCurrentIngestionRecord(provider);\n if (record) {\n const next_action_at = new Date();\n next_action_at.setTime(next_action_at.getTime() + 24 * 60 * 60 * 1000);\n await this.manager.updateByName(provider, {\n next_action: 'nothing (done)',\n ingestion_completed_at: new Date(),\n next_action_at,\n status: 'resting',\n });\n res.json({\n success: true,\n message: `${provider}: Current ingestion canceled.`,\n });\n } else {\n const providers: string[] = await this.manager.listProviders();\n if (providers.includes(provider)) {\n this.logger.debug(`${provider} - Ingestion record found`);\n res.json({\n success: true,\n message: 'Provider is currently restarting, please wait.',\n });\n } else {\n res.status(404).json({\n success: false,\n message: `Provider '${provider}' not found`,\n });\n }\n }\n });\n\n // Wipe out all ingestion records for the provider and pause for 24 hours\n router.delete(PROVIDER_BASE_PATH, async (req, res) => {\n const { provider } = req.params;\n const result = await this.manager.purgeAndResetProvider(provider);\n res.json(result);\n });\n\n // Get the ingestion marks for the current cycle\n router.get(`${PROVIDER_BASE_PATH}/marks`, async (req, res) => {\n const { provider } = req.params;\n const record = await this.manager.getCurrentIngestionRecord(provider);\n if (record) {\n const id = record.id;\n const records = await this.manager.getAllMarks(id);\n res.json({ success: true, records });\n } else {\n const providers: string[] = await this.manager.listProviders();\n if (providers.includes(provider)) {\n this.logger.debug(`${provider} - Ingestion record found`);\n res.json({\n success: true,\n message: 'No records yet (provider is restarting)',\n });\n } else {\n this.logger.error(\n `${provider} - No ingestion record found in the database!`,\n );\n res.status(404).json({\n success: false,\n status: {},\n last_error: `Provider '${provider}' not found`,\n });\n }\n }\n });\n\n router.delete(`${PROVIDER_BASE_PATH}/marks`, async (req, res) => {\n const { provider } = req.params;\n const deletions = await this.manager.clearFinishedIngestions(provider);\n\n res.json({\n success: true,\n message: `Expired marks for provider '${provider}' removed.`,\n deletions,\n });\n });\n\n router.use(errorHandler());\n\n return router;\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport class Deferred<T> implements Promise<T> {\n #resolve?: (value: T) => void;\n #reject?: (error: Error) => void;\n\n public get resolve() {\n return this.#resolve!;\n }\n public get reject() {\n return this.#reject!;\n }\n\n public then: Promise<T>['then'];\n public catch: Promise<T>['catch'];\n public finally: Promise<T>['finally'];\n\n public constructor() {\n const promise = new Promise<T>((resolve, reject) => {\n this.#resolve = resolve;\n this.#reject = reject;\n });\n\n this.then = promise.then.bind(promise);\n this.catch = promise.catch.bind(promise);\n this.finally = promise.finally.bind(promise);\n }\n\n [Symbol.toStringTag]: 'Deferred' = 'Deferred';\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ConfigService,\n LoggerService,\n SchedulerService,\n} from '@backstage/backend-plugin-api';\nimport { loggerToWinstonLogger } from '@backstage/backend-common';\nimport { stringifyError } from '@backstage/errors';\nimport {\n EntityProvider,\n EntityProviderConnection,\n} from '@backstage/plugin-catalog-node';\nimport express from 'express';\nimport { Knex } from 'knex';\nimport { Duration } from 'luxon';\nimport { IncrementalIngestionDatabaseManager } from '../database/IncrementalIngestionDatabaseManager';\nimport { applyDatabaseMigrations } from '../database/migrations';\nimport { IncrementalIngestionEngine } from '../engine/IncrementalIngestionEngine';\nimport { IncrementalProviderRouter } from '../router/routes';\nimport {\n IncrementalEntityProvider,\n IncrementalEntityProviderOptions,\n} from '../types';\nimport { Deferred } from '../util';\n\n/**\n * Helps in the creation of the catalog entity providers that wrap the\n * incremental ones.\n */\nexport class WrapperProviders {\n private migrate: Promise<void> | undefined;\n private numberOfProvidersToConnect = 0;\n private readonly readySignal = new Deferred<void>();\n\n constructor(\n private readonly options: {\n config: ConfigService;\n logger: LoggerService;\n client: Knex;\n scheduler: SchedulerService;\n applyDatabaseMigrations?: typeof applyDatabaseMigrations;\n },\n ) {}\n\n wrap(\n provider: IncrementalEntityProvider<unknown, unknown>,\n options: IncrementalEntityProviderOptions,\n ): EntityProvider {\n this.numberOfProvidersToConnect += 1;\n return {\n getProviderName: () => provider.getProviderName(),\n connect: async connection => {\n await this.startProvider(provider, options, connection);\n this.numberOfProvidersToConnect -= 1;\n if (this.numberOfProvidersToConnect === 0) {\n this.readySignal.resolve();\n }\n },\n };\n }\n\n async adminRouter(): Promise<express.Router> {\n return await new IncrementalProviderRouter(\n new IncrementalIngestionDatabaseManager({ client: this.options.client }),\n loggerToWinstonLogger(this.options.logger),\n ).createRouter();\n }\n\n private async startProvider(\n provider: IncrementalEntityProvider<unknown, unknown>,\n providerOptions: IncrementalEntityProviderOptions,\n connection: EntityProviderConnection,\n ) {\n const logger = loggerToWinstonLogger(\n this.options.logger.child({\n entityProvider: provider.getProviderName(),\n }),\n );\n\n try {\n if (!this.migrate) {\n this.migrate = Promise.resolve().then(async () => {\n const apply =\n this.options.applyDatabaseMigrations ?? applyDatabaseMigrations;\n await apply(this.options.client);\n });\n }\n\n await this.migrate;\n\n const { burstInterval, burstLength, restLength } = providerOptions;\n\n logger.info(`Connecting`);\n\n const manager = new IncrementalIngestionDatabaseManager({\n client: this.options.client,\n });\n const engine = new IncrementalIngestionEngine({\n ...providerOptions,\n ready: this.readySignal,\n manager,\n logger,\n provider,\n restLength,\n connection,\n });\n\n const frequency = Duration.isDuration(burstInterval)\n ? burstInterval\n : Duration.fromObject(burstInterval);\n const length = Duration.isDuration(burstLength)\n ? burstLength\n : Duration.fromObject(burstLength);\n\n await this.options.scheduler.scheduleTask({\n id: provider.getProviderName(),\n fn: engine.taskFn.bind(engine),\n frequency,\n timeout: length,\n });\n } catch (error) {\n logger.warn(\n `Failed to initialize incremental ingestion provider ${provider.getProviderName()}, ${stringifyError(\n error,\n )}`,\n );\n throw error;\n }\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createBackendModule,\n} from '@backstage/backend-plugin-api';\nimport { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';\nimport {\n IncrementalEntityProvider,\n IncrementalEntityProviderOptions,\n} from '../types';\nimport { WrapperProviders } from './WrapperProviders';\n\n/**\n * Registers the incremental entity provider with the catalog processing extension point.\n *\n * @alpha\n */\nexport const incrementalIngestionEntityProviderCatalogModule =\n createBackendModule(\n (options: {\n providers: Array<{\n provider: IncrementalEntityProvider<unknown, unknown>;\n options: IncrementalEntityProviderOptions;\n }>;\n }) => ({\n pluginId: 'catalog',\n moduleId: 'incrementalIngestionEntityProvider',\n register(env) {\n env.registerInit({\n deps: {\n catalog: catalogProcessingExtensionPoint,\n config: coreServices.config,\n database: coreServices.database,\n httpRouter: coreServices.httpRouter,\n logger: coreServices.logger,\n scheduler: coreServices.scheduler,\n },\n async init({\n catalog,\n config,\n database,\n httpRouter,\n logger,\n scheduler,\n }) {\n const client = await database.getClient();\n\n const providers = new WrapperProviders({\n config,\n logger,\n client,\n scheduler,\n });\n\n for (const entry of options.providers) {\n const wrapped = providers.wrap(entry.provider, entry.options);\n catalog.addEntityProvider(wrapped);\n }\n\n httpRouter.use(await providers.adminRouter());\n },\n });\n },\n }),\n );\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n IncrementalEntityProvider,\n IncrementalEntityProviderOptions,\n PluginEnvironment,\n} from '../types';\nimport { CatalogBuilder as CoreCatalogBuilder } from '@backstage/plugin-catalog-backend';\nimport { Duration } from 'luxon';\nimport { Knex } from 'knex';\nimport { IncrementalIngestionEngine } from '../engine/IncrementalIngestionEngine';\nimport { applyDatabaseMigrations } from '../database/migrations';\nimport { IncrementalIngestionDatabaseManager } from '../database/IncrementalIngestionDatabaseManager';\nimport { IncrementalProviderRouter } from '../router/routes';\nimport { Deferred } from '../util';\n\n/** @public */\nexport class IncrementalCatalogBuilder {\n /**\n * Creates the incremental catalog builder, which extends the regular catalog builder.\n * @param env - PluginEnvironment\n * @param builder - CatalogBuilder\n * @returns IncrementalCatalogBuilder\n */\n static async create(env: PluginEnvironment, builder: CoreCatalogBuilder) {\n const client = await env.database.getClient();\n const manager = new IncrementalIngestionDatabaseManager({ client });\n return new IncrementalCatalogBuilder(env, builder, client, manager);\n }\n\n private ready: Deferred<void>;\n\n private constructor(\n private env: PluginEnvironment,\n private builder: CoreCatalogBuilder,\n private client: Knex,\n private manager: IncrementalIngestionDatabaseManager,\n ) {\n this.ready = new Deferred<void>();\n }\n\n async build() {\n await applyDatabaseMigrations(this.client);\n this.ready.resolve();\n\n const routerLogger = this.env.logger.child({\n router: 'IncrementalProviderAdmin',\n });\n\n const incrementalAdminRouter = await new IncrementalProviderRouter(\n this.manager,\n routerLogger,\n ).createRouter();\n\n return { incrementalAdminRouter };\n }\n\n addIncrementalEntityProvider<TCursor, TContext>(\n provider: IncrementalEntityProvider<TCursor, TContext>,\n options: IncrementalEntityProviderOptions,\n ) {\n const { burstInterval, burstLength, restLength } = options;\n const { logger: catalogLogger, scheduler } = this.env;\n const ready = this.ready;\n\n const manager = this.manager;\n\n this.builder.addEntityProvider({\n getProviderName: provider.getProviderName.bind(provider),\n async connect(connection) {\n const logger = catalogLogger.child({\n entityProvider: provider.getProviderName(),\n });\n\n logger.info(`Connecting`);\n\n const engine = new IncrementalIngestionEngine({\n ...options,\n ready,\n manager,\n logger,\n provider,\n restLength,\n connection,\n });\n\n const frequency = Duration.isDuration(burstInterval)\n ? burstInterval\n : Duration.fromObject(burstInterval);\n const length = Duration.isDuration(burstLength)\n ? burstLength\n : Duration.fromObject(burstLength);\n\n await scheduler.scheduleTask({\n id: provider.getProviderName(),\n fn: engine.taskFn.bind(engine),\n frequency,\n timeout: length,\n });\n },\n });\n }\n}\n"],"names":["v4","stringifyEntityRef","resolvePackagePath","Duration","stringifyError","performance","Router","express","errorHandler","loggerToWinstonLogger","createBackendModule","catalogProcessingExtensionPoint","coreServices"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../src/database/IncrementalIngestionDatabaseManager.ts","../src/database/tables.ts","../src/database/migrations.ts","../src/engine/IncrementalIngestionEngine.ts","../src/router/paths.ts","../src/router/routes.ts","../src/util.ts","../src/module/WrapperProviders.ts","../src/module/incrementalIngestionEntityProviderCatalogModule.ts","../src/service/IncrementalCatalogBuilder.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Knex } from 'knex';\nimport type { DeferredEntity } from '@backstage/plugin-catalog-backend';\nimport { stringifyEntityRef } from '@backstage/catalog-model';\nimport { Duration } from 'luxon';\nimport { v4 } from 'uuid';\nimport {\n IngestionRecord,\n IngestionRecordUpdate,\n IngestionUpsert,\n MarkRecord,\n MarkRecordInsert,\n} from './tables';\n\nexport class IncrementalIngestionDatabaseManager {\n private client: Knex;\n\n constructor(options: { client: Knex }) {\n this.client = options.client;\n }\n\n /**\n * Performs an update to the ingestion record with matching `id`.\n * @param options - IngestionRecordUpdate\n */\n async updateIngestionRecordById(options: IngestionRecordUpdate) {\n await this.client.transaction(async tx => {\n const { ingestionId, update } = options;\n await tx('ingestions').where('id', ingestionId).update(update);\n });\n }\n\n /**\n * Performs an update to the ingestion record with matching provider name. Will only update active records.\n * @param provider - string\n * @param update - Partial<IngestionUpsertIFace>\n */\n async updateIngestionRecordByProvider(\n provider: string,\n update: Partial<IngestionUpsert>,\n ) {\n await this.client.transaction(async tx => {\n await tx('ingestions')\n .where('provider_name', provider)\n .andWhere('completion_ticket', 'open')\n .update(update);\n });\n }\n\n /**\n * Performs an insert into the `ingestions` table with the supplied values.\n * @param record - IngestionUpsertIFace\n */\n async insertIngestionRecord(record: IngestionUpsert) {\n await this.client.transaction(async tx => {\n await tx('ingestions').insert(record);\n });\n }\n\n private async deleteMarkEntities(\n tx: Knex.Transaction,\n ids: { id: string }[],\n ) {\n const chunks: { id: string }[][] = [];\n for (let i = 0; i < ids.length; i += 100) {\n const chunk = ids.slice(i, i + 100);\n chunks.push(chunk);\n }\n\n let deleted = 0;\n\n for (const chunk of chunks) {\n const chunkDeleted = await tx('ingestion_mark_entities')\n .delete()\n .whereIn(\n 'id',\n chunk.map(entry => entry.id),\n );\n deleted += chunkDeleted;\n }\n\n return deleted;\n }\n\n /**\n * Finds the current ingestion record for the named provider.\n * @param provider - string\n * @returns IngestionRecord | undefined\n */\n async getCurrentIngestionRecord(provider: string) {\n return await this.client.transaction(async tx => {\n const record = await tx<IngestionRecord>('ingestions')\n .where('provider_name', provider)\n .andWhere('completion_ticket', 'open')\n .first();\n return record;\n });\n }\n\n /**\n * Finds the last ingestion record for the named provider.\n * @param provider - string\n * @returns IngestionRecord | undefined\n */\n async getPreviousIngestionRecord(provider: string) {\n return await this.client.transaction(async tx => {\n return await tx<IngestionRecord>('ingestions')\n .where('provider_name', provider)\n .andWhereNot('completion_ticket', 'open')\n .first();\n });\n }\n\n /**\n * Removes all entries from `ingestion_marks_entities`, `ingestion_marks`, and `ingestions`\n * for prior ingestions that completed (i.e., have a `completion_ticket` value other than 'open').\n * @param provider - string\n * @returns A count of deletions for each record type.\n */\n async clearFinishedIngestions(provider: string) {\n return await this.client.transaction(async tx => {\n const markEntitiesDeleted = await tx('ingestion_mark_entities')\n .delete()\n .whereIn(\n 'ingestion_mark_id',\n tx('ingestion_marks')\n .select('id')\n .whereIn(\n 'ingestion_id',\n tx('ingestions')\n .select('id')\n .where('provider_name', provider)\n .andWhereNot('completion_ticket', 'open'),\n ),\n );\n\n const marksDeleted = await tx('ingestion_marks')\n .delete()\n .whereIn(\n 'ingestion_id',\n tx('ingestions')\n .select('id')\n .where('provider_name', provider)\n .andWhereNot('completion_ticket', 'open'),\n );\n\n const ingestionsDeleted = await tx('ingestions')\n .delete()\n .where('provider_name', provider)\n .andWhereNot('completion_ticket', 'open');\n\n return {\n deletions: {\n markEntitiesDeleted,\n marksDeleted,\n ingestionsDeleted,\n },\n };\n });\n }\n\n /**\n * Automatically cleans up duplicate ingestion records if they were accidentally created.\n * Any ingestion record where the `rest_completed_at` is null (meaning it is active) AND\n * the ingestionId is incorrect is a duplicate ingestion record.\n * @param ingestionId - string\n * @param provider - string\n */\n async clearDuplicateIngestions(ingestionId: string, provider: string) {\n await this.client.transaction(async tx => {\n const invalid = await tx<IngestionRecord>('ingestions')\n .where('provider_name', provider)\n .andWhere('rest_completed_at', null)\n .andWhereNot('id', ingestionId);\n\n if (invalid.length > 0) {\n await tx('ingestions').delete().whereIn('id', invalid);\n await tx('ingestion_mark_entities')\n .delete()\n .whereIn(\n 'ingestion_mark_id',\n tx('ingestion_marks').select('id').whereIn('ingestion_id', invalid),\n );\n await tx('ingestion_marks').delete().whereIn('ingestion_id', invalid);\n }\n });\n }\n\n /**\n * This method fully purges and resets all ingestion records for the named provider, and\n * leaves it in a paused state.\n * @param provider - string\n * @returns Counts of all deleted ingestion records\n */\n async purgeAndResetProvider(provider: string) {\n return await this.client.transaction(async tx => {\n const ingestionIDs: { id: string }[] = await tx('ingestions')\n .select('id')\n .where('provider_name', provider);\n\n const markIDs: { id: string }[] =\n ingestionIDs.length > 0\n ? await tx('ingestion_marks')\n .select('id')\n .whereIn(\n 'ingestion_id',\n ingestionIDs.map(entry => entry.id),\n )\n : [];\n\n const markEntityIDs: { id: string }[] =\n markIDs.length > 0\n ? await tx('ingestion_mark_entities')\n .select('id')\n .whereIn(\n 'ingestion_mark_id',\n markIDs.map(entry => entry.id),\n )\n : [];\n\n const markEntitiesDeleted = await this.deleteMarkEntities(\n tx,\n markEntityIDs,\n );\n\n const marksDeleted =\n markIDs.length > 0\n ? await tx('ingestion_marks')\n .delete()\n .whereIn(\n 'ingestion_id',\n ingestionIDs.map(entry => entry.id),\n )\n : 0;\n\n const ingestionsDeleted = await tx('ingestions')\n .delete()\n .where('provider_name', provider);\n\n const next_action_at = new Date();\n next_action_at.setTime(next_action_at.getTime() + 24 * 60 * 60 * 1000);\n\n await this.insertIngestionRecord({\n id: v4(),\n next_action: 'rest',\n provider_name: provider,\n next_action_at,\n ingestion_completed_at: new Date(),\n status: 'resting',\n completion_ticket: 'open',\n });\n\n return { provider, ingestionsDeleted, marksDeleted, markEntitiesDeleted };\n });\n }\n\n /**\n * This method is used to remove entity records from the ingestion_mark_entities\n * table by their entity reference.\n */\n async deleteEntityRecordsByRef(entities: { entityRef: string }[]) {\n const refs = entities.map(e => e.entityRef);\n await this.client.transaction(async tx => {\n await tx('ingestion_mark_entities').delete().whereIn('ref', refs);\n });\n }\n\n /**\n * Creates a new ingestion record.\n * @param provider - string\n * @returns A new ingestion record\n */\n async createProviderIngestionRecord(provider: string) {\n const ingestionId = v4();\n const nextAction = 'ingest';\n try {\n await this.insertIngestionRecord({\n id: ingestionId,\n next_action: nextAction,\n provider_name: provider,\n status: 'bursting',\n completion_ticket: 'open',\n });\n return { ingestionId, nextAction, attempts: 0, nextActionAt: Date.now() };\n } catch (_e) {\n // Creating the ingestion record failed. Return undefined.\n return undefined;\n }\n }\n\n /**\n * Computes which entities to remove, if any, at the end of a burst.\n * @param provider - string\n * @param ingestionId - string\n * @returns All entities to remove for this burst.\n */\n async computeRemoved(provider: string, ingestionId: string) {\n const previousIngestion = await this.getPreviousIngestionRecord(provider);\n return await this.client.transaction(async tx => {\n const count = await tx('ingestion_mark_entities')\n .count({ total: 'ingestion_mark_entities.ref' })\n .join(\n 'ingestion_marks',\n 'ingestion_marks.id',\n 'ingestion_mark_entities.ingestion_mark_id',\n )\n .join('ingestions', 'ingestions.id', 'ingestion_marks.ingestion_id')\n .where('ingestions.id', ingestionId);\n\n const total = count.reduce((acc, cur) => acc + (cur.total as number), 0);\n\n const removed: { entityRef: string }[] = [];\n if (previousIngestion) {\n const stale: { ref: string }[] = await tx('ingestion_mark_entities')\n .select('ingestion_mark_entities.ref')\n .join(\n 'ingestion_marks',\n 'ingestion_marks.id',\n 'ingestion_mark_entities.ingestion_mark_id',\n )\n .join('ingestions', 'ingestions.id', 'ingestion_marks.ingestion_id')\n .where('ingestions.id', previousIngestion.id);\n\n removed.push(\n ...stale.map(e => {\n return { entityRef: e.ref };\n }),\n );\n }\n\n return { total, removed };\n });\n }\n\n /**\n * Performs a lookup of all providers that have duplicate active ingestion records.\n * @returns An array of all duplicate active ingestions\n */\n async healthcheck() {\n return await this.client.transaction(async tx => {\n const records = await tx<{ id: string; provider_name: string }>(\n 'ingestions',\n )\n .distinct('id', 'provider_name')\n .where('rest_completed_at', null);\n return records;\n });\n }\n\n /**\n * Skips any wait time for the next action to run.\n * @param provider - string\n */\n async triggerNextProviderAction(provider: string) {\n await this.updateIngestionRecordByProvider(provider, {\n next_action_at: new Date(),\n });\n }\n\n /**\n * Purges the following tables:\n * * `ingestions`\n * * `ingestion_marks`\n * * `ingestion_mark_entities`\n *\n * This function leaves the ingestions table with all providers in a paused state.\n * @returns Results from cleaning up all ingestion tables.\n */\n async cleanupProviders() {\n const providers = await this.listProviders();\n\n const ingestionsDeleted = await this.purgeTable('ingestions');\n\n const next_action_at = new Date();\n next_action_at.setTime(next_action_at.getTime() + 24 * 60 * 60 * 1000);\n\n for (const provider of providers) {\n await this.insertIngestionRecord({\n id: v4(),\n next_action: 'rest',\n provider_name: provider,\n next_action_at,\n ingestion_completed_at: new Date(),\n status: 'resting',\n completion_ticket: 'open',\n });\n }\n\n const ingestionMarksDeleted = await this.purgeTable('ingestion_marks');\n const markEntitiesDeleted = await this.purgeTable(\n 'ingestion_mark_entities',\n );\n\n return { ingestionsDeleted, ingestionMarksDeleted, markEntitiesDeleted };\n }\n\n /**\n * Configures the current ingestion record to ingest a burst.\n * @param ingestionId - string\n */\n async setProviderIngesting(ingestionId: string) {\n await this.updateIngestionRecordById({\n ingestionId,\n update: { next_action: 'ingest' },\n });\n }\n\n /**\n * Indicates the provider is currently ingesting a burst.\n * @param ingestionId - string\n */\n async setProviderBursting(ingestionId: string) {\n await this.updateIngestionRecordById({\n ingestionId,\n update: { status: 'bursting' },\n });\n }\n\n /**\n * Finalizes the current ingestion record to indicate that the post-ingestion rest period is complete.\n * @param ingestionId - string\n */\n async setProviderComplete(ingestionId: string) {\n await this.updateIngestionRecordById({\n ingestionId,\n update: {\n next_action: 'nothing (done)',\n rest_completed_at: new Date(),\n status: 'complete',\n completion_ticket: v4(),\n },\n });\n }\n\n /**\n * Marks ingestion as complete and starts the post-ingestion rest cycle.\n * @param ingestionId - string\n * @param restLength - Duration\n */\n async setProviderResting(ingestionId: string, restLength: Duration) {\n await this.updateIngestionRecordById({\n ingestionId,\n update: {\n next_action: 'rest',\n next_action_at: new Date(Date.now() + restLength.as('milliseconds')),\n ingestion_completed_at: new Date(),\n status: 'resting',\n },\n });\n }\n\n /**\n * Marks ingestion as paused after a burst completes.\n * @param ingestionId - string\n */\n async setProviderInterstitial(ingestionId: string) {\n await this.updateIngestionRecordById({\n ingestionId,\n update: { attempts: 0, status: 'interstitial' },\n });\n }\n\n /**\n * Starts the cancel process for the current ingestion.\n * @param ingestionId - string\n * @param message - string (optional)\n */\n async setProviderCanceling(ingestionId: string, message?: string) {\n const update: Partial<IngestionUpsert> = {\n next_action: 'cancel',\n last_error: message ? message : undefined,\n next_action_at: new Date(),\n status: 'canceling',\n };\n await this.updateIngestionRecordById({ ingestionId, update });\n }\n\n /**\n * Completes the cancel process and triggers a new ingestion.\n * @param ingestionId - string\n */\n async setProviderCanceled(ingestionId: string) {\n await this.updateIngestionRecordById({\n ingestionId,\n update: {\n next_action: 'nothing (canceled)',\n rest_completed_at: new Date(),\n status: 'complete',\n completion_ticket: v4(),\n },\n });\n }\n\n /**\n * Configures the current ingestion to wait and retry, due to a data source error.\n * @param ingestionId - string\n * @param attempts - number\n * @param error - Error\n * @param backoffLength - number\n */\n async setProviderBackoff(\n ingestionId: string,\n attempts: number,\n error: Error,\n backoffLength: number,\n ) {\n await this.updateIngestionRecordById({\n ingestionId,\n update: {\n next_action: 'backoff',\n attempts: attempts + 1,\n last_error: String(error),\n next_action_at: new Date(Date.now() + backoffLength),\n status: 'backing off',\n },\n });\n }\n\n /**\n * Returns the last record from `ingestion_marks` for the supplied ingestionId.\n * @param ingestionId - string\n * @returns MarkRecord | undefined\n */\n async getLastMark(ingestionId: string) {\n return await this.client.transaction(async tx => {\n const mark = await tx<MarkRecord>('ingestion_marks')\n .where('ingestion_id', ingestionId)\n .orderBy('sequence', 'desc')\n .first();\n return mark;\n });\n }\n\n /**\n * Returns the first record from `ingestion_marks` for the supplied ingestionId.\n * @param ingestionId - string\n * @returns MarkRecord | undefined\n */\n async getFirstMark(ingestionId: string) {\n return await this.client.transaction(async tx => {\n const mark = await tx<MarkRecord>('ingestion_marks')\n .where('ingestion_id', ingestionId)\n .orderBy('sequence', 'asc')\n .first();\n return mark;\n });\n }\n\n async getAllMarks(ingestionId: string) {\n return await this.client.transaction(async tx => {\n const marks = await tx<MarkRecord>('ingestion_marks')\n .where('ingestion_id', ingestionId)\n .orderBy('sequence', 'desc');\n return marks;\n });\n }\n\n /**\n * Performs an insert into the `ingestion_marks` table with the supplied values.\n * @param options - MarkRecordInsert\n */\n async createMark(options: MarkRecordInsert) {\n const { record } = options;\n await this.client.transaction(async tx => {\n await tx('ingestion_marks').insert(record);\n });\n }\n /**\n * Performs an upsert to the `ingestion_mark_entities` table for all deferred entities.\n * @param markId - string\n * @param entities - DeferredEntity[]\n */\n async createMarkEntities(markId: string, entities: DeferredEntity[]) {\n const refs = entities.map(e => stringifyEntityRef(e.entity));\n\n await this.client.transaction(async tx => {\n const existingRefsArray = (\n await tx<{ ref: string }>('ingestion_mark_entities')\n .select('ref')\n .whereIn('ref', refs)\n ).map(e => e.ref);\n\n const existingRefsSet = new Set(existingRefsArray);\n\n const newRefs = refs.filter(e => !existingRefsSet.has(e));\n\n await tx('ingestion_mark_entities')\n .update('ingestion_mark_id', markId)\n .whereIn('ref', existingRefsArray);\n\n if (newRefs.length > 0) {\n await tx('ingestion_mark_entities').insert(\n newRefs.map(ref => ({\n id: v4(),\n ingestion_mark_id: markId,\n ref,\n })),\n );\n }\n });\n }\n\n /**\n * Deletes the entire content of a table, and returns the number of records deleted.\n * @param table - string\n * @returns number\n */\n async purgeTable(table: string) {\n return await this.client.transaction(async tx => {\n return await tx(table).delete();\n });\n }\n\n /**\n * Returns a list of all providers.\n * @returns string[]\n */\n async listProviders() {\n return await this.client.transaction(async tx => {\n const providers = await tx<{ provider_name: string }>(\n 'ingestions',\n ).distinct('provider_name');\n return providers.map(entry => entry.provider_name);\n });\n }\n\n async updateByName(provider: string, update: Partial<IngestionUpsert>) {\n await this.updateIngestionRecordByProvider(provider, update);\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport const DB_MIGRATIONS_TABLE = 'incremental_ingestion__knex_migrations';\n\n/**\n * The shape of data inserted into or updated in the `ingestions` table.\n */\nexport interface IngestionUpsert {\n /**\n * The ingestion record id.\n */\n id?: string;\n /**\n * The next action the incremental entity provider will take.\n */\n next_action:\n | 'rest'\n | 'ingest'\n | 'backoff'\n | 'cancel'\n | 'nothing (done)'\n | 'nothing (canceled)';\n /**\n * Current status of the incremental entity provider.\n */\n status:\n | 'complete'\n | 'bursting'\n | 'resting'\n | 'canceling'\n | 'interstitial'\n | 'backing off';\n /**\n * The name of the incremental entity provider being updated.\n */\n provider_name: string;\n /**\n * Date/time stamp for when the next action will trigger.\n */\n next_action_at?: Date;\n /**\n * A record of the last error generated by the incremental entity provider.\n */\n last_error?: string | null;\n /**\n * The number of attempts the provider has attempted during the current cycle.\n */\n attempts?: number;\n /**\n * Date/time stamp for the completion of ingestion.\n */\n ingestion_completed_at?: Date | string | null;\n /**\n * Date/time stamp for the end of the rest cycle before the next ingestion.\n */\n rest_completed_at?: Date | string | null;\n /**\n * A record of the finalized status of the ingestion record. Values are either 'open' or a uuid.\n */\n completion_ticket: string;\n}\n\n/**\n * This interface is for updating an existing ingestion record.\n */\nexport interface IngestionRecordUpdate {\n ingestionId: string;\n update: Partial<IngestionUpsert>;\n}\n\n/**\n * The expected response from the `ingestion_marks` table.\n */\nexport interface MarkRecord {\n id: string;\n sequence: number;\n ingestion_id: string;\n cursor: string;\n created_at: string;\n}\n\n/**\n * The expected response from the `ingestions` table.\n */\nexport interface IngestionRecord extends IngestionUpsert {\n id: string;\n next_action_at: Date;\n /**\n * The date/time the ingestion record was created.\n */\n created_at: string;\n}\n\n/**\n * This interface supplies all the values for adding an ingestion mark.\n */\nexport interface MarkRecordInsert {\n record: {\n id: string;\n ingestion_id: string;\n cursor: unknown;\n sequence: number;\n };\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { resolvePackagePath } from '@backstage/backend-common';\nimport { Knex } from 'knex';\nimport { DB_MIGRATIONS_TABLE } from './tables';\n\nexport async function applyDatabaseMigrations(knex: Knex): Promise<void> {\n const migrationsDir = resolvePackagePath(\n '@backstage/plugin-catalog-backend-module-incremental-ingestion',\n 'migrations',\n );\n\n await knex.migrate.latest({\n directory: migrationsDir,\n tableName: DB_MIGRATIONS_TABLE,\n });\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { DeferredEntity } from '@backstage/plugin-catalog-backend';\nimport { IterationEngine, IterationEngineOptions } from '../types';\nimport { IncrementalIngestionDatabaseManager } from '../database/IncrementalIngestionDatabaseManager';\nimport { performance } from 'perf_hooks';\nimport { Duration, DurationObjectUnits } from 'luxon';\nimport { v4 } from 'uuid';\nimport { stringifyError } from '@backstage/errors';\nimport { EventParams, EventSubscriber } from '@backstage/plugin-events-node';\n\nexport class IncrementalIngestionEngine\n implements IterationEngine, EventSubscriber\n{\n private readonly restLength: Duration;\n private readonly backoff: DurationObjectUnits[];\n\n private manager: IncrementalIngestionDatabaseManager;\n\n constructor(private options: IterationEngineOptions) {\n this.manager = options.manager;\n this.restLength = Duration.fromObject(options.restLength);\n this.backoff = options.backoff ?? [\n { minutes: 1 },\n { minutes: 5 },\n { minutes: 30 },\n { hours: 3 },\n ];\n }\n\n async taskFn(signal: AbortSignal) {\n try {\n this.options.logger.debug('Begin tick');\n await this.handleNextAction(signal);\n } catch (error) {\n this.options.logger.error(`${error}`);\n throw error;\n } finally {\n this.options.logger.debug('End tick');\n }\n }\n\n async handleNextAction(signal: AbortSignal) {\n await this.options.ready;\n\n const result = await this.getCurrentAction();\n if (result) {\n const { ingestionId, nextActionAt, nextAction, attempts } = result;\n\n switch (nextAction) {\n case 'rest':\n if (Date.now() > nextActionAt) {\n await this.manager.clearFinishedIngestions(\n this.options.provider.getProviderName(),\n );\n this.options.logger.info(\n `incremental-engine: Ingestion ${ingestionId} rest period complete. Ingestion will start again`,\n );\n\n await this.manager.setProviderComplete(ingestionId);\n } else {\n this.options.logger.info(\n `incremental-engine: Ingestion '${ingestionId}' rest period continuing`,\n );\n }\n break;\n case 'ingest':\n try {\n await this.manager.setProviderBursting(ingestionId);\n const done = await this.ingestOneBurst(ingestionId, signal);\n if (done) {\n this.options.logger.info(\n `incremental-engine: Ingestion '${ingestionId}' complete, transitioning to rest period of ${this.restLength.toHuman()}`,\n );\n await this.manager.setProviderResting(\n ingestionId,\n this.restLength,\n );\n } else {\n await this.manager.setProviderInterstitial(ingestionId);\n this.options.logger.info(\n `incremental-engine: Ingestion '${ingestionId}' continuing`,\n );\n }\n } catch (error) {\n if (\n (error as Error).message &&\n (error as Error).message === 'CANCEL'\n ) {\n this.options.logger.info(\n `incremental-engine: Ingestion '${ingestionId}' canceled`,\n );\n await this.manager.setProviderCanceling(\n ingestionId,\n (error as Error).message,\n );\n } else {\n const currentBackoff = Duration.fromObject(\n this.backoff[Math.min(this.backoff.length - 1, attempts)],\n );\n\n const backoffLength = currentBackoff.as('milliseconds');\n this.options.logger.error(\n `incremental-engine: Ingestion '${ingestionId}' failed`,\n error,\n );\n\n const truncatedError = stringifyError(error).substring(0, 700);\n this.options.logger.error(\n `incremental-engine: Ingestion '${ingestionId}' threw an error during ingestion burst. Ingestion will backoff for ${currentBackoff.toHuman()} (${truncatedError})`,\n );\n\n await this.manager.setProviderBackoff(\n ingestionId,\n attempts,\n error as Error,\n backoffLength,\n );\n }\n }\n break;\n case 'backoff':\n if (Date.now() > nextActionAt) {\n this.options.logger.info(\n `incremental-engine: Ingestion '${ingestionId}' backoff complete, will attempt to resume`,\n );\n await this.manager.setProviderIngesting(ingestionId);\n } else {\n this.options.logger.info(\n `incremental-engine: Ingestion '${ingestionId}' backoff continuing`,\n );\n }\n break;\n case 'cancel':\n this.options.logger.info(\n `incremental-engine: Ingestion '${ingestionId}' canceling, will restart`,\n );\n await this.manager.setProviderCanceled(ingestionId);\n break;\n default:\n this.options.logger.error(\n `incremental-engine: Ingestion '${ingestionId}' received unknown action '${nextAction}'`,\n );\n }\n } else {\n this.options.logger.error(\n `incremental-engine: Engine tried to create duplicate ingestion record for provider '${this.options.provider.getProviderName()}'.`,\n );\n }\n }\n\n async getCurrentAction() {\n const providerName = this.options.provider.getProviderName();\n const record = await this.manager.getCurrentIngestionRecord(providerName);\n if (record) {\n this.options.logger.info(\n `incremental-engine: Ingestion record found: '${record.id}'`,\n );\n return {\n ingestionId: record.id,\n nextAction: record.next_action as 'rest' | 'ingest' | 'backoff',\n attempts: record.attempts as number,\n nextActionAt: record.next_action_at.valueOf() as number,\n };\n }\n const result = await this.manager.createProviderIngestionRecord(\n providerName,\n );\n if (result) {\n this.options.logger.info(\n `incremental-engine: Ingestion record created: '${result.ingestionId}'`,\n );\n }\n return result;\n }\n\n async ingestOneBurst(id: string, signal: AbortSignal) {\n const lastMark = await this.manager.getLastMark(id);\n\n const cursor = lastMark ? lastMark.cursor : undefined;\n let sequence = lastMark ? lastMark.sequence + 1 : 0;\n\n const start = performance.now();\n let count = 0;\n let done = false;\n this.options.logger.info(\n `incremental-engine: Ingestion '${id}' burst initiated`,\n );\n\n await this.options.provider.around(async (context: unknown) => {\n let next = await this.options.provider.next(context, cursor);\n count++;\n for (;;) {\n done = next.done;\n await this.mark({\n id,\n sequence,\n entities: next?.entities,\n done: next.done,\n cursor: next?.cursor,\n });\n if (signal.aborted || next.done) {\n break;\n } else {\n next = await this.options.provider.next(context, next.cursor);\n count++;\n sequence++;\n }\n }\n });\n\n this.options.logger.info(\n `incremental-engine: Ingestion '${id}' burst complete. (${count} batches in ${Math.round(\n performance.now() - start,\n )}ms).`,\n );\n return done;\n }\n\n async mark(options: {\n id: string;\n sequence: number;\n entities?: DeferredEntity[];\n done: boolean;\n cursor?: unknown;\n }) {\n const { id, sequence, entities, done, cursor } = options;\n this.options.logger.debug(\n `incremental-engine: Ingestion '${id}': MARK ${\n entities ? entities.length : 0\n } entities, cursor: ${\n cursor ? JSON.stringify(cursor) : 'none'\n }, done: ${done}`,\n );\n const markId = v4();\n\n await this.manager.createMark({\n record: {\n id: markId,\n ingestion_id: id,\n cursor,\n sequence,\n },\n });\n\n if (entities && entities.length > 0) {\n await this.manager.createMarkEntities(markId, entities);\n }\n\n const added =\n entities?.map(deferred => ({\n ...deferred,\n entity: {\n ...deferred.entity,\n metadata: {\n ...deferred.entity.metadata,\n annotations: {\n ...deferred.entity.metadata.annotations,\n },\n },\n },\n })) ?? [];\n\n const removed: { entityRef: string }[] = [];\n\n if (done) {\n this.options.logger.info(\n `incremental-engine: Ingestion '${id}': Final page reached, calculating removed entities`,\n );\n const result = await this.manager.computeRemoved(\n this.options.provider.getProviderName(),\n id,\n );\n\n const { total } = result;\n\n let doRemoval = true;\n if (this.options.rejectEmptySourceCollections) {\n if (total === 0) {\n this.options.logger.error(\n `incremental-engine: Ingestion '${id}': Rejecting empty entity collection!`,\n );\n doRemoval = false;\n }\n }\n\n if (this.options.rejectRemovalsAbovePercentage) {\n // If the total entities upserted in this ingestion is 0, then\n // 100% of entities are stale and marked for removal.\n const percentRemoved =\n total > 0 ? (result.removed.length / total) * 100 : 100;\n if (percentRemoved <= this.options.rejectRemovalsAbovePercentage) {\n this.options.logger.info(\n `incremental-engine: Ingestion '${id}': Removing ${result.removed.length} entities that have no matching assets`,\n );\n } else {\n const notice = `Attempted to remove ${percentRemoved}% of matching entities!`;\n this.options.logger.error(\n `incremental-engine: Ingestion '${id}': ${notice}`,\n );\n await this.manager.updateIngestionRecordById({\n ingestionId: id,\n update: {\n last_error: `REMOVAL_THRESHOLD exceeded on ingestion mark ${markId}: ${notice}`,\n },\n });\n doRemoval = false;\n }\n }\n if (doRemoval) {\n removed.push(...result.removed);\n }\n }\n\n await this.options.connection.applyMutation({\n type: 'delta',\n added,\n removed,\n });\n }\n\n async onEvent(params: EventParams): Promise<void> {\n const { topic } = params;\n if (!this.supportsEventTopics().includes(topic)) {\n return;\n }\n\n const { logger, provider, connection } = this.options;\n const providerName = provider.getProviderName();\n logger.debug(`incremental-engine: ${providerName} received ${topic} event`);\n\n if (!provider.eventHandler) {\n return;\n }\n\n const delta = provider.eventHandler.onEvent(params);\n\n if (delta) {\n if (delta.added.length > 0) {\n const ingestionRecord = await this.manager.getCurrentIngestionRecord(\n providerName,\n );\n\n if (!ingestionRecord) {\n logger.debug(\n `incremental-engine: ${providerName} skipping delta addition because incremental ingestion is restarting.`,\n );\n } else {\n const mark =\n ingestionRecord.status === 'resting'\n ? await this.manager.getLastMark(ingestionRecord.id)\n : await this.manager.getFirstMark(ingestionRecord.id);\n\n if (!mark) {\n throw new Error(\n `Cannot apply delta, page records are missing! Please re-run incremental ingestion for ${providerName}.`,\n );\n }\n await this.manager.createMarkEntities(mark.id, delta.added);\n }\n }\n\n if (delta.removed.length > 0) {\n await this.manager.deleteEntityRecordsByRef(delta.removed);\n }\n\n await connection.applyMutation({\n type: 'delta',\n ...delta,\n });\n logger.debug(\n `incremental-engine: ${providerName} processed delta from '${topic}' event`,\n );\n } else {\n logger.warn(\n `incremental-engine: Rejected delta from '${topic}' event - empty or invalid`,\n );\n }\n }\n\n supportsEventTopics(): string[] {\n const { provider } = this.options;\n const topics = provider.eventHandler\n ? provider.eventHandler.supportsEventTopics()\n : [];\n return topics;\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport const PROVIDER_CLEANUP = '/incremental/cleanup';\nexport const PROVIDER_HEALTH = '/incremental/health';\nexport const PROVIDER_BASE_PATH = '/incremental/providers/:provider';\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { errorHandler } from '@backstage/backend-common';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { Logger } from 'winston';\nimport { IncrementalIngestionDatabaseManager } from '../database/IncrementalIngestionDatabaseManager';\nimport { PROVIDER_BASE_PATH, PROVIDER_CLEANUP, PROVIDER_HEALTH } from './paths';\n\nexport class IncrementalProviderRouter {\n private manager: IncrementalIngestionDatabaseManager;\n private logger: Logger;\n\n constructor(manager: IncrementalIngestionDatabaseManager, logger: Logger) {\n this.manager = manager;\n this.logger = logger;\n }\n\n async createRouter() {\n const router = Router();\n router.use(express.json());\n\n // Get the overall health of all incremental providers\n router.get(PROVIDER_HEALTH, async (_, res) => {\n const records = await this.manager.healthcheck();\n const providers = records.map(record => record.provider_name);\n const duplicates = [\n ...new Set(providers.filter((e, i, a) => a.indexOf(e) !== i)),\n ];\n\n if (duplicates.length > 0) {\n res.json({ healthy: false, duplicateIngestions: duplicates });\n } else {\n res.json({ healthy: true });\n }\n });\n\n // Clean up and pause all providers\n router.post(PROVIDER_CLEANUP, async (_, res) => {\n const result = await this.manager.cleanupProviders();\n res.json(result);\n });\n\n // Get basic status of the provider\n router.get(PROVIDER_BASE_PATH, async (req, res) => {\n const { provider } = req.params;\n const record = await this.manager.getCurrentIngestionRecord(provider);\n if (record) {\n res.json({\n success: true,\n status: {\n current_action: record.status,\n next_action_at: new Date(record.next_action_at),\n },\n last_error: record.last_error,\n });\n } else {\n const providers: string[] = await this.manager.listProviders();\n if (providers.includes(provider)) {\n res.json({\n success: true,\n status: {\n current_action: 'rest complete, waiting to start',\n },\n });\n } else {\n this.logger.error(\n `${provider} - No ingestion record found in the database!`,\n );\n res.status(404).json({\n success: false,\n status: {},\n last_error: `Provider '${provider}' not found`,\n });\n }\n }\n });\n\n // Trigger the provider's next action\n router.post(`${PROVIDER_BASE_PATH}/trigger`, async (req, res) => {\n const { provider } = req.params;\n const record = await this.manager.getCurrentIngestionRecord(provider);\n if (record) {\n await this.manager.triggerNextProviderAction(provider);\n res.json({\n success: true,\n message: `${provider}: Next action triggered.`,\n });\n } else {\n const providers: string[] = await this.manager.listProviders();\n if (providers.includes(provider)) {\n this.logger.debug(`${provider} - Ingestion record found`);\n res.json({\n success: true,\n message: 'Unable to trigger next action (provider is restarting)',\n });\n } else {\n res.status(404).json({\n success: false,\n message: `Provider '${provider}' not found`,\n });\n }\n }\n });\n\n // Start a brand-new ingestion cycle for the provider.\n // (Cancel's the current run if active, or marks it complete if resting)\n router.post(`${PROVIDER_BASE_PATH}/start`, async (req, res) => {\n const { provider } = req.params;\n\n const record = await this.manager.getCurrentIngestionRecord(provider);\n if (record) {\n const ingestionId = record.id;\n if (record.status === 'resting') {\n await this.manager.setProviderComplete(ingestionId);\n } else {\n await this.manager.setProviderCanceling(ingestionId);\n }\n res.json({\n success: true,\n message: `${provider}: Next cycle triggered.`,\n });\n } else {\n const providers: string[] = await this.manager.listProviders();\n if (providers.includes(provider)) {\n this.logger.debug(`${provider} - Ingestion record found`);\n res.json({\n success: true,\n message: 'Provider is already restarting',\n });\n } else {\n res.status(404).json({\n success: false,\n message: `Provider '${provider}' not found`,\n });\n }\n }\n });\n\n // Stop the provider and pause it for 24 hours\n router.post(`${PROVIDER_BASE_PATH}/cancel`, async (req, res) => {\n const { provider } = req.params;\n const record = await this.manager.getCurrentIngestionRecord(provider);\n if (record) {\n const next_action_at = new Date();\n next_action_at.setTime(next_action_at.getTime() + 24 * 60 * 60 * 1000);\n await this.manager.updateByName(provider, {\n next_action: 'nothing (done)',\n ingestion_completed_at: new Date(),\n next_action_at,\n status: 'resting',\n });\n res.json({\n success: true,\n message: `${provider}: Current ingestion canceled.`,\n });\n } else {\n const providers: string[] = await this.manager.listProviders();\n if (providers.includes(provider)) {\n this.logger.debug(`${provider} - Ingestion record found`);\n res.json({\n success: true,\n message: 'Provider is currently restarting, please wait.',\n });\n } else {\n res.status(404).json({\n success: false,\n message: `Provider '${provider}' not found`,\n });\n }\n }\n });\n\n // Wipe out all ingestion records for the provider and pause for 24 hours\n router.delete(PROVIDER_BASE_PATH, async (req, res) => {\n const { provider } = req.params;\n const result = await this.manager.purgeAndResetProvider(provider);\n res.json(result);\n });\n\n // Get the ingestion marks for the current cycle\n router.get(`${PROVIDER_BASE_PATH}/marks`, async (req, res) => {\n const { provider } = req.params;\n const record = await this.manager.getCurrentIngestionRecord(provider);\n if (record) {\n const id = record.id;\n const records = await this.manager.getAllMarks(id);\n res.json({ success: true, records });\n } else {\n const providers: string[] = await this.manager.listProviders();\n if (providers.includes(provider)) {\n this.logger.debug(`${provider} - Ingestion record found`);\n res.json({\n success: true,\n message: 'No records yet (provider is restarting)',\n });\n } else {\n this.logger.error(\n `${provider} - No ingestion record found in the database!`,\n );\n res.status(404).json({\n success: false,\n status: {},\n last_error: `Provider '${provider}' not found`,\n });\n }\n }\n });\n\n router.delete(`${PROVIDER_BASE_PATH}/marks`, async (req, res) => {\n const { provider } = req.params;\n const deletions = await this.manager.clearFinishedIngestions(provider);\n\n res.json({\n success: true,\n message: `Expired marks for provider '${provider}' removed.`,\n deletions,\n });\n });\n\n router.use(errorHandler());\n\n return router;\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport class Deferred<T> implements Promise<T> {\n #resolve?: (value: T) => void;\n #reject?: (error: Error) => void;\n\n public get resolve() {\n return this.#resolve!;\n }\n public get reject() {\n return this.#reject!;\n }\n\n public then: Promise<T>['then'];\n public catch: Promise<T>['catch'];\n public finally: Promise<T>['finally'];\n\n public constructor() {\n const promise = new Promise<T>((resolve, reject) => {\n this.#resolve = resolve;\n this.#reject = reject;\n });\n\n this.then = promise.then.bind(promise);\n this.catch = promise.catch.bind(promise);\n this.finally = promise.finally.bind(promise);\n }\n\n [Symbol.toStringTag]: 'Deferred' = 'Deferred';\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ConfigService,\n LoggerService,\n SchedulerService,\n} from '@backstage/backend-plugin-api';\nimport { loggerToWinstonLogger } from '@backstage/backend-common';\nimport { stringifyError } from '@backstage/errors';\nimport {\n EntityProvider,\n EntityProviderConnection,\n} from '@backstage/plugin-catalog-node';\nimport express from 'express';\nimport { Knex } from 'knex';\nimport { Duration } from 'luxon';\nimport { IncrementalIngestionDatabaseManager } from '../database/IncrementalIngestionDatabaseManager';\nimport { applyDatabaseMigrations } from '../database/migrations';\nimport { IncrementalIngestionEngine } from '../engine/IncrementalIngestionEngine';\nimport { IncrementalProviderRouter } from '../router/routes';\nimport {\n IncrementalEntityProvider,\n IncrementalEntityProviderOptions,\n} from '../types';\nimport { Deferred } from '../util';\n\n/**\n * Helps in the creation of the catalog entity providers that wrap the\n * incremental ones.\n */\nexport class WrapperProviders {\n private migrate: Promise<void> | undefined;\n private numberOfProvidersToConnect = 0;\n private readonly readySignal = new Deferred<void>();\n\n constructor(\n private readonly options: {\n config: ConfigService;\n logger: LoggerService;\n client: Knex;\n scheduler: SchedulerService;\n applyDatabaseMigrations?: typeof applyDatabaseMigrations;\n },\n ) {}\n\n wrap(\n provider: IncrementalEntityProvider<unknown, unknown>,\n options: IncrementalEntityProviderOptions,\n ): EntityProvider {\n this.numberOfProvidersToConnect += 1;\n return {\n getProviderName: () => provider.getProviderName(),\n connect: async connection => {\n await this.startProvider(provider, options, connection);\n this.numberOfProvidersToConnect -= 1;\n if (this.numberOfProvidersToConnect === 0) {\n this.readySignal.resolve();\n }\n },\n };\n }\n\n async adminRouter(): Promise<express.Router> {\n return await new IncrementalProviderRouter(\n new IncrementalIngestionDatabaseManager({ client: this.options.client }),\n loggerToWinstonLogger(this.options.logger),\n ).createRouter();\n }\n\n private async startProvider(\n provider: IncrementalEntityProvider<unknown, unknown>,\n providerOptions: IncrementalEntityProviderOptions,\n connection: EntityProviderConnection,\n ) {\n const logger = loggerToWinstonLogger(\n this.options.logger.child({\n entityProvider: provider.getProviderName(),\n }),\n );\n\n try {\n if (!this.migrate) {\n this.migrate = Promise.resolve().then(async () => {\n const apply =\n this.options.applyDatabaseMigrations ?? applyDatabaseMigrations;\n await apply(this.options.client);\n });\n }\n\n await this.migrate;\n\n const { burstInterval, burstLength, restLength } = providerOptions;\n\n logger.info(`Connecting`);\n\n const manager = new IncrementalIngestionDatabaseManager({\n client: this.options.client,\n });\n const engine = new IncrementalIngestionEngine({\n ...providerOptions,\n ready: this.readySignal,\n manager,\n logger,\n provider,\n restLength,\n connection,\n });\n\n const frequency = Duration.isDuration(burstInterval)\n ? burstInterval\n : Duration.fromObject(burstInterval);\n const length = Duration.isDuration(burstLength)\n ? burstLength\n : Duration.fromObject(burstLength);\n\n await this.options.scheduler.scheduleTask({\n id: provider.getProviderName(),\n fn: engine.taskFn.bind(engine),\n frequency,\n timeout: length,\n });\n } catch (error) {\n logger.warn(\n `Failed to initialize incremental ingestion provider ${provider.getProviderName()}, ${stringifyError(\n error,\n )}`,\n );\n throw error;\n }\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createBackendModule,\n} from '@backstage/backend-plugin-api';\nimport { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';\nimport {\n IncrementalEntityProvider,\n IncrementalEntityProviderOptions,\n} from '../types';\nimport { WrapperProviders } from './WrapperProviders';\n\n/**\n * Registers the incremental entity provider with the catalog processing extension point.\n *\n * @alpha\n */\nexport const incrementalIngestionEntityProviderCatalogModule =\n createBackendModule(\n (options: {\n providers: Array<{\n provider: IncrementalEntityProvider<unknown, unknown>;\n options: IncrementalEntityProviderOptions;\n }>;\n }) => ({\n pluginId: 'catalog',\n moduleId: 'incrementalIngestionEntityProvider',\n register(env) {\n env.registerInit({\n deps: {\n catalog: catalogProcessingExtensionPoint,\n config: coreServices.config,\n database: coreServices.database,\n httpRouter: coreServices.httpRouter,\n logger: coreServices.logger,\n scheduler: coreServices.scheduler,\n },\n async init({\n catalog,\n config,\n database,\n httpRouter,\n logger,\n scheduler,\n }) {\n const client = await database.getClient();\n\n const providers = new WrapperProviders({\n config,\n logger,\n client,\n scheduler,\n });\n\n for (const entry of options.providers) {\n const wrapped = providers.wrap(entry.provider, entry.options);\n catalog.addEntityProvider(wrapped);\n }\n\n httpRouter.use(await providers.adminRouter());\n },\n });\n },\n }),\n );\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n IncrementalEntityProvider,\n IncrementalEntityProviderOptions,\n PluginEnvironment,\n} from '../types';\nimport { CatalogBuilder as CoreCatalogBuilder } from '@backstage/plugin-catalog-backend';\nimport { Duration } from 'luxon';\nimport { Knex } from 'knex';\nimport { IncrementalIngestionEngine } from '../engine/IncrementalIngestionEngine';\nimport { applyDatabaseMigrations } from '../database/migrations';\nimport { IncrementalIngestionDatabaseManager } from '../database/IncrementalIngestionDatabaseManager';\nimport { IncrementalProviderRouter } from '../router/routes';\nimport { Deferred } from '../util';\nimport { EventParams, EventSubscriber } from '@backstage/plugin-events-node';\n\n/** @public */\nexport class IncrementalCatalogBuilder {\n /**\n * Creates the incremental catalog builder, which extends the regular catalog builder.\n * @param env - PluginEnvironment\n * @param builder - CatalogBuilder\n * @returns IncrementalCatalogBuilder\n */\n static async create(env: PluginEnvironment, builder: CoreCatalogBuilder) {\n const client = await env.database.getClient();\n const manager = new IncrementalIngestionDatabaseManager({ client });\n return new IncrementalCatalogBuilder(env, builder, client, manager);\n }\n\n private ready: Deferred<void>;\n\n private constructor(\n private env: PluginEnvironment,\n private builder: CoreCatalogBuilder,\n private client: Knex,\n private manager: IncrementalIngestionDatabaseManager,\n ) {\n this.ready = new Deferred<void>();\n }\n\n async build() {\n await applyDatabaseMigrations(this.client);\n this.ready.resolve();\n\n const routerLogger = this.env.logger.child({\n router: 'IncrementalProviderAdmin',\n });\n\n const incrementalAdminRouter = await new IncrementalProviderRouter(\n this.manager,\n routerLogger,\n ).createRouter();\n\n return { incrementalAdminRouter };\n }\n\n addIncrementalEntityProvider<TCursor, TContext>(\n provider: IncrementalEntityProvider<TCursor, TContext>,\n options: IncrementalEntityProviderOptions,\n ): EventSubscriber {\n const { burstInterval, burstLength, restLength } = options;\n const { logger: catalogLogger, scheduler } = this.env;\n const ready = this.ready;\n\n const manager = this.manager;\n\n let engine: IncrementalIngestionEngine;\n\n this.builder.addEntityProvider({\n getProviderName: provider.getProviderName.bind(provider),\n async connect(connection) {\n const logger = catalogLogger.child({\n entityProvider: provider.getProviderName(),\n });\n\n logger.info(`Connecting`);\n\n engine = new IncrementalIngestionEngine({\n ...options,\n ready,\n manager,\n logger,\n provider,\n restLength,\n connection,\n });\n\n const frequency = Duration.isDuration(burstInterval)\n ? burstInterval\n : Duration.fromObject(burstInterval);\n const length = Duration.isDuration(burstLength)\n ? burstLength\n : Duration.fromObject(burstLength);\n\n await scheduler.scheduleTask({\n id: provider.getProviderName(),\n fn: engine.taskFn.bind(engine),\n frequency,\n timeout: length,\n });\n },\n });\n\n return {\n onEvent: (params: EventParams) => engine.onEvent(params),\n supportsEventTopics() {\n return engine.supportsEventTopics();\n },\n };\n }\n}\n"],"names":["v4","stringifyEntityRef","resolvePackagePath","Duration","stringifyError","performance","Router","express","errorHandler","loggerToWinstonLogger","createBackendModule","catalogProcessingExtensionPoint","coreServices"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type { Config } from '@backstage/config';
|
|
|
12
12
|
import type { DeferredEntity } from '@backstage/plugin-catalog-backend';
|
|
13
13
|
import type { DurationObjectUnits } from 'luxon';
|
|
14
14
|
import { EventParams } from '@backstage/plugin-events-node';
|
|
15
|
+
import { EventSubscriber } from '@backstage/plugin-events-node';
|
|
15
16
|
import type { Logger } from 'winston';
|
|
16
17
|
import type { PermissionEvaluator } from '@backstage/plugin-permission-common';
|
|
17
18
|
import type { PluginDatabaseManager } from '@backstage/backend-common';
|
|
@@ -53,7 +54,7 @@ export declare class IncrementalCatalogBuilder {
|
|
|
53
54
|
build(): Promise<{
|
|
54
55
|
incrementalAdminRouter: Router;
|
|
55
56
|
}>;
|
|
56
|
-
addIncrementalEntityProvider<TCursor, TContext>(provider: IncrementalEntityProvider<TCursor, TContext>, options: IncrementalEntityProviderOptions):
|
|
57
|
+
addIncrementalEntityProvider<TCursor, TContext>(provider: IncrementalEntityProvider<TCursor, TContext>, options: IncrementalEntityProviderOptions): EventSubscriber;
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
/**
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-catalog-backend-module-incremental-ingestion",
|
|
3
3
|
"description": "An entity provider for streaming large asset sources into the catalog",
|
|
4
|
-
"version": "0.2.0-next.
|
|
4
|
+
"version": "0.2.0-next.2",
|
|
5
5
|
"main": "dist/index.cjs.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"license": "Apache-2.0",
|
|
@@ -33,16 +33,16 @@
|
|
|
33
33
|
"postpack": "backstage-cli package postpack"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@backstage/backend-common": "^0.18.2-next.
|
|
37
|
-
"@backstage/backend-plugin-api": "^0.
|
|
38
|
-
"@backstage/backend-tasks": "^0.4.3-next.
|
|
39
|
-
"@backstage/backend-test-utils": "^0.1.34-next.
|
|
40
|
-
"@backstage/catalog-model": "^1.
|
|
36
|
+
"@backstage/backend-common": "^0.18.2-next.2",
|
|
37
|
+
"@backstage/backend-plugin-api": "^0.4.0-next.2",
|
|
38
|
+
"@backstage/backend-tasks": "^0.4.3-next.2",
|
|
39
|
+
"@backstage/backend-test-utils": "^0.1.34-next.2",
|
|
40
|
+
"@backstage/catalog-model": "^1.2.0-next.1",
|
|
41
41
|
"@backstage/config": "^1.0.6",
|
|
42
42
|
"@backstage/errors": "^1.1.4",
|
|
43
|
-
"@backstage/plugin-catalog-backend": "^1.7.2-next.
|
|
44
|
-
"@backstage/plugin-catalog-node": "^1.3.3-next.
|
|
45
|
-
"@backstage/plugin-events-node": "^0.2.3-next.
|
|
43
|
+
"@backstage/plugin-catalog-backend": "^1.7.2-next.2",
|
|
44
|
+
"@backstage/plugin-catalog-node": "^1.3.3-next.2",
|
|
45
|
+
"@backstage/plugin-events-node": "^0.2.3-next.2",
|
|
46
46
|
"@backstage/plugin-permission-common": "^0.7.3",
|
|
47
47
|
"@types/express": "^4.17.6",
|
|
48
48
|
"@types/luxon": "^3.0.0",
|
|
@@ -55,9 +55,9 @@
|
|
|
55
55
|
"winston": "^3.2.1"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@backstage/backend-app-api": "^0.
|
|
59
|
-
"@backstage/cli": "^0.22.1",
|
|
60
|
-
"@backstage/plugin-catalog-backend": "^1.7.2-next.
|
|
58
|
+
"@backstage/backend-app-api": "^0.4.0-next.2",
|
|
59
|
+
"@backstage/cli": "^0.22.2-next.1",
|
|
60
|
+
"@backstage/plugin-catalog-backend": "^1.7.2-next.2"
|
|
61
61
|
},
|
|
62
62
|
"files": [
|
|
63
63
|
"alpha",
|