@docker-harpoon/core 0.1.3 → 0.1.5
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/dist/__tests__/bindings.test.js +9 -5
- package/dist/__tests__/container.test.js +30 -9
- package/dist/__tests__/database.test.js +0 -14
- package/dist/__tests__/docker-infra.template.d.ts +2 -0
- package/dist/__tests__/docker-infra.template.d.ts.map +1 -0
- package/dist/__tests__/docker-infra.template.js +174 -0
- package/dist/__tests__/test-setup.d.ts +9 -0
- package/dist/__tests__/test-setup.d.ts.map +1 -0
- package/dist/__tests__/test-setup.js +27 -0
- package/dist/api/index.d.ts +1 -1
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/promise.d.ts +13 -3
- package/dist/api/promise.d.ts.map +1 -1
- package/dist/api/promise.js +33 -18
- package/dist/bindings/index.d.ts +2 -2
- package/dist/bindings/index.d.ts.map +1 -1
- package/dist/bindings/index.js +1 -1
- package/dist/bindings/types.d.ts.map +1 -1
- package/dist/bindings/types.js +1 -3
- package/dist/build-strategies/types.d.ts.map +1 -1
- package/dist/config-patchers/index.d.ts.map +1 -1
- package/dist/config-patchers/types.d.ts.map +1 -1
- package/dist/dockerfile-transformers/core.d.ts.map +1 -1
- package/dist/dockerfile-transformers/core.js +2 -5
- package/dist/dockerfile-transformers/index.d.ts.map +1 -1
- package/dist/dockerfile-transformers/types.d.ts.map +1 -1
- package/dist/errors.d.ts +6 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +3 -3
- package/dist/helpers/database.d.ts.map +1 -1
- package/dist/helpers/database.js +1 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/resources/container.d.ts +25 -2
- package/dist/resources/container.d.ts.map +1 -1
- package/dist/resources/container.js +301 -77
- package/dist/resources/image.d.ts.map +1 -1
- package/dist/resources/image.js +14 -35
- package/dist/resources/index.d.ts +1 -1
- package/dist/resources/index.d.ts.map +1 -1
- package/dist/resources/network.d.ts.map +1 -1
- package/dist/resources/network.js +23 -9
- package/dist/resources/schemas.d.ts +178 -18
- package/dist/resources/schemas.d.ts.map +1 -1
- package/dist/resources/schemas.js +2 -1
- package/dist/services/CircuitBreaker.d.ts +83 -0
- package/dist/services/CircuitBreaker.d.ts.map +1 -0
- package/dist/services/CircuitBreaker.js +164 -0
- package/dist/services/ContainerPool.d.ts +82 -0
- package/dist/services/ContainerPool.d.ts.map +1 -0
- package/dist/services/ContainerPool.js +186 -0
- package/dist/services/DockerBatcher.d.ts +74 -0
- package/dist/services/DockerBatcher.d.ts.map +1 -0
- package/dist/services/DockerBatcher.js +107 -0
- package/dist/services/DockerClient.d.ts +125 -0
- package/dist/services/DockerClient.d.ts.map +1 -0
- package/dist/services/DockerClient.js +220 -0
- package/dist/services/DockerErrors.d.ts +145 -0
- package/dist/services/DockerErrors.d.ts.map +1 -0
- package/dist/services/DockerErrors.js +224 -0
- package/dist/services/DockerRateLimiter.d.ts +80 -0
- package/dist/services/DockerRateLimiter.d.ts.map +1 -0
- package/dist/services/DockerRateLimiter.js +93 -0
- package/dist/services/EventBus.d.ts +126 -0
- package/dist/services/EventBus.d.ts.map +1 -0
- package/dist/services/EventBus.js +111 -0
- package/dist/services/Harpoon.d.ts +151 -0
- package/dist/services/Harpoon.d.ts.map +1 -0
- package/dist/services/Harpoon.js +148 -0
- package/dist/services/HarpoonConfig.d.ts +60 -0
- package/dist/services/HarpoonConfig.d.ts.map +1 -0
- package/dist/services/HarpoonConfig.js +67 -0
- package/dist/services/HarpoonLogger.d.ts +36 -0
- package/dist/services/HarpoonLogger.d.ts.map +1 -0
- package/dist/services/HarpoonLogger.js +94 -0
- package/dist/services/ReadinessCoordinator.d.ts +128 -0
- package/dist/services/ReadinessCoordinator.d.ts.map +1 -0
- package/dist/services/ReadinessCoordinator.js +170 -0
- package/dist/services/ResourceTracker.d.ts +74 -0
- package/dist/services/ResourceTracker.d.ts.map +1 -0
- package/dist/services/ResourceTracker.js +145 -0
- package/dist/services/index.d.ts +29 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +47 -0
- package/dist/testing/helpers.d.ts +114 -0
- package/dist/testing/helpers.d.ts.map +1 -0
- package/dist/testing/helpers.js +140 -0
- package/dist/testing/index.d.ts +29 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +47 -0
- package/dist/testing/mocks.d.ts +66 -0
- package/dist/testing/mocks.d.ts.map +1 -0
- package/dist/testing/mocks.js +224 -0
- package/dist/utils/process.d.ts +24 -0
- package/dist/utils/process.d.ts.map +1 -0
- package/dist/utils/process.js +49 -0
- package/package.json +12 -8
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DockerRateLimiter Service
|
|
3
|
+
*
|
|
4
|
+
* Provides semaphore-based rate limiting for Docker API operations.
|
|
5
|
+
* Prevents overwhelming the Docker daemon with too many concurrent requests.
|
|
6
|
+
*/
|
|
7
|
+
import { Context, Effect, Layer, Schedule, Duration } from 'effect';
|
|
8
|
+
import { HarpoonConfig } from './HarpoonConfig';
|
|
9
|
+
/**
|
|
10
|
+
* DockerRateLimiter service tag for dependency injection.
|
|
11
|
+
*/
|
|
12
|
+
export class DockerRateLimiter extends Context.Tag('@harpoon/DockerRateLimiter')() {
|
|
13
|
+
}
|
|
14
|
+
// ============ Retry Schedules (Step 2) ============
|
|
15
|
+
/**
|
|
16
|
+
* Exponential backoff schedule for transient Docker API errors.
|
|
17
|
+
*
|
|
18
|
+
* - 5 retries maximum
|
|
19
|
+
* - Base delay: 100ms, exponentially increasing
|
|
20
|
+
* - Max delay: 30 seconds
|
|
21
|
+
* - Includes jitter to prevent thundering herd
|
|
22
|
+
*/
|
|
23
|
+
export const dockerRetrySchedule = Schedule.exponential(Duration.millis(100), 2).pipe(Schedule.jittered, Schedule.either(Schedule.recurs(5)), Schedule.upTo(Duration.seconds(30)));
|
|
24
|
+
/**
|
|
25
|
+
* Aggressive retry schedule for cleanup operations.
|
|
26
|
+
*
|
|
27
|
+
* - 3 retries maximum
|
|
28
|
+
* - Base delay: 200ms
|
|
29
|
+
* - Max delay: 10 seconds
|
|
30
|
+
* - Quick cleanup attempts with short delays
|
|
31
|
+
*/
|
|
32
|
+
export const cleanupRetrySchedule = Schedule.exponential(Duration.millis(200), 2).pipe(Schedule.jittered, Schedule.either(Schedule.recurs(3)), Schedule.upTo(Duration.seconds(10)));
|
|
33
|
+
/**
|
|
34
|
+
* Health check schedule with fixed intervals.
|
|
35
|
+
*
|
|
36
|
+
* - 1 second between checks
|
|
37
|
+
* - Used for container readiness polling
|
|
38
|
+
*/
|
|
39
|
+
export const healthCheckSchedule = Schedule.spaced(Duration.seconds(1));
|
|
40
|
+
// ============ Live Implementation ============
|
|
41
|
+
/**
|
|
42
|
+
* Creates a simple semaphore-based rate limiter using Effect.
|
|
43
|
+
*/
|
|
44
|
+
const makeSemaphore = (permits) => Effect.gen(function* () {
|
|
45
|
+
// Use Effect.makeSemaphore for a simple counting semaphore
|
|
46
|
+
const semaphore = yield* Effect.makeSemaphore(permits);
|
|
47
|
+
return {
|
|
48
|
+
withPermit: (effect) => semaphore.withPermits(1)(effect),
|
|
49
|
+
withPermits: (count) => (effect) => semaphore.withPermits(count)(effect),
|
|
50
|
+
// Return the current permits - Effect semaphores don't expose available count
|
|
51
|
+
// so we just return the configured limit as an approximation
|
|
52
|
+
available: () => Effect.succeed(permits),
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
/**
|
|
56
|
+
* Live implementation of DockerRateLimiter.
|
|
57
|
+
*
|
|
58
|
+
* Uses HarpoonConfig.parallelLimit to determine semaphore size.
|
|
59
|
+
*/
|
|
60
|
+
export const DockerRateLimiterLive = Layer.scoped(DockerRateLimiter, Effect.gen(function* () {
|
|
61
|
+
const config = yield* HarpoonConfig;
|
|
62
|
+
const semaphore = yield* makeSemaphore(config.parallelLimit);
|
|
63
|
+
yield* Effect.logDebug('DockerRateLimiter initialized').pipe(Effect.annotateLogs({ permits: config.parallelLimit }));
|
|
64
|
+
return {
|
|
65
|
+
_tag: 'DockerRateLimiter',
|
|
66
|
+
withPermit: semaphore.withPermit,
|
|
67
|
+
withPermits: semaphore.withPermits,
|
|
68
|
+
available: semaphore.available,
|
|
69
|
+
};
|
|
70
|
+
}));
|
|
71
|
+
/**
|
|
72
|
+
* Test implementation with unlimited permits.
|
|
73
|
+
*
|
|
74
|
+
* Useful for unit tests that don't need rate limiting.
|
|
75
|
+
*/
|
|
76
|
+
export const DockerRateLimiterTest = Layer.succeed(DockerRateLimiter, {
|
|
77
|
+
_tag: 'DockerRateLimiter',
|
|
78
|
+
withPermit: (effect) => effect,
|
|
79
|
+
withPermits: () => (effect) => effect,
|
|
80
|
+
available: () => Effect.succeed(Infinity),
|
|
81
|
+
});
|
|
82
|
+
/**
|
|
83
|
+
* Create a custom test rate limiter with specific permit count.
|
|
84
|
+
*/
|
|
85
|
+
export const makeDockerRateLimiterTest = (permits) => Layer.scoped(DockerRateLimiter, Effect.gen(function* () {
|
|
86
|
+
const semaphore = yield* makeSemaphore(permits);
|
|
87
|
+
return {
|
|
88
|
+
_tag: 'DockerRateLimiter',
|
|
89
|
+
withPermit: semaphore.withPermit,
|
|
90
|
+
withPermits: semaphore.withPermits,
|
|
91
|
+
available: semaphore.available,
|
|
92
|
+
};
|
|
93
|
+
}));
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EventBus Service
|
|
3
|
+
*
|
|
4
|
+
* Provides a publish/subscribe event system for Harpoon resource lifecycle events.
|
|
5
|
+
* Uses Effect's PubSub for type-safe, concurrent event distribution.
|
|
6
|
+
*/
|
|
7
|
+
import { Context, Effect, Layer, Stream, Scope } from 'effect';
|
|
8
|
+
/**
|
|
9
|
+
* Container lifecycle event types.
|
|
10
|
+
*/
|
|
11
|
+
export type ContainerEventType = 'Created' | 'Started' | 'Stopped' | 'Destroyed' | 'Error';
|
|
12
|
+
/**
|
|
13
|
+
* Network lifecycle event types.
|
|
14
|
+
*/
|
|
15
|
+
export type NetworkEventType = 'Created' | 'Destroyed' | 'Connected' | 'Disconnected';
|
|
16
|
+
/**
|
|
17
|
+
* Container lifecycle event.
|
|
18
|
+
*/
|
|
19
|
+
export interface ContainerEvent {
|
|
20
|
+
readonly _tag: 'ContainerEvent';
|
|
21
|
+
readonly type: ContainerEventType;
|
|
22
|
+
readonly containerId: string;
|
|
23
|
+
readonly containerName: string;
|
|
24
|
+
readonly timestamp: Date;
|
|
25
|
+
readonly metadata?: Record<string, unknown>;
|
|
26
|
+
readonly error?: Error;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Network lifecycle event.
|
|
30
|
+
*/
|
|
31
|
+
export interface NetworkEvent {
|
|
32
|
+
readonly _tag: 'NetworkEvent';
|
|
33
|
+
readonly type: NetworkEventType;
|
|
34
|
+
readonly networkId: string;
|
|
35
|
+
readonly networkName: string;
|
|
36
|
+
readonly timestamp: Date;
|
|
37
|
+
readonly metadata?: Record<string, unknown>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Database lifecycle event (extends container events with DB-specific info).
|
|
41
|
+
*/
|
|
42
|
+
export interface DatabaseEvent {
|
|
43
|
+
readonly _tag: 'DatabaseEvent';
|
|
44
|
+
readonly type: ContainerEventType;
|
|
45
|
+
readonly containerId: string;
|
|
46
|
+
readonly databaseName: string;
|
|
47
|
+
readonly databaseType: string;
|
|
48
|
+
readonly timestamp: Date;
|
|
49
|
+
readonly connectionString?: string;
|
|
50
|
+
readonly metadata?: Record<string, unknown>;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Union type of all Harpoon events.
|
|
54
|
+
*/
|
|
55
|
+
export type HarpoonEvent = ContainerEvent | NetworkEvent | DatabaseEvent;
|
|
56
|
+
/**
|
|
57
|
+
* Create a container event.
|
|
58
|
+
*/
|
|
59
|
+
export declare const containerEvent: (type: ContainerEventType, containerId: string, containerName: string, options?: {
|
|
60
|
+
metadata?: Record<string, unknown>;
|
|
61
|
+
error?: Error;
|
|
62
|
+
} | undefined) => ContainerEvent;
|
|
63
|
+
/**
|
|
64
|
+
* Create a network event.
|
|
65
|
+
*/
|
|
66
|
+
export declare const networkEvent: (type: NetworkEventType, networkId: string, networkName: string, options?: {
|
|
67
|
+
metadata?: Record<string, unknown>;
|
|
68
|
+
} | undefined) => NetworkEvent;
|
|
69
|
+
/**
|
|
70
|
+
* Create a database event.
|
|
71
|
+
*/
|
|
72
|
+
export declare const databaseEvent: (type: ContainerEventType, containerId: string, databaseName: string, databaseType: string, options?: {
|
|
73
|
+
connectionString?: string;
|
|
74
|
+
metadata?: Record<string, unknown>;
|
|
75
|
+
} | undefined) => DatabaseEvent;
|
|
76
|
+
/**
|
|
77
|
+
* EventBus service interface.
|
|
78
|
+
*/
|
|
79
|
+
export interface EventBusService {
|
|
80
|
+
readonly _tag: 'EventBus';
|
|
81
|
+
/**
|
|
82
|
+
* Publish an event to all subscribers.
|
|
83
|
+
*/
|
|
84
|
+
readonly publish: (event: HarpoonEvent) => Effect.Effect<boolean>;
|
|
85
|
+
/**
|
|
86
|
+
* Subscribe to all events.
|
|
87
|
+
* Returns a Stream that emits events as they are published.
|
|
88
|
+
* Requires Scope for queue management.
|
|
89
|
+
*/
|
|
90
|
+
readonly subscribe: () => Effect.Effect<Stream.Stream<HarpoonEvent, never>, never, Scope.Scope>;
|
|
91
|
+
/**
|
|
92
|
+
* Subscribe to container events only.
|
|
93
|
+
* Requires Scope for queue management.
|
|
94
|
+
*/
|
|
95
|
+
readonly subscribeContainers: () => Effect.Effect<Stream.Stream<ContainerEvent, never>, never, Scope.Scope>;
|
|
96
|
+
/**
|
|
97
|
+
* Subscribe to network events only.
|
|
98
|
+
* Requires Scope for queue management.
|
|
99
|
+
*/
|
|
100
|
+
readonly subscribeNetworks: () => Effect.Effect<Stream.Stream<NetworkEvent, never>, never, Scope.Scope>;
|
|
101
|
+
/**
|
|
102
|
+
* Subscribe to database events only.
|
|
103
|
+
* Requires Scope for queue management.
|
|
104
|
+
*/
|
|
105
|
+
readonly subscribeDatabases: () => Effect.Effect<Stream.Stream<DatabaseEvent, never>, never, Scope.Scope>;
|
|
106
|
+
/**
|
|
107
|
+
* Get the number of current subscribers.
|
|
108
|
+
*/
|
|
109
|
+
readonly subscriberCount: () => Effect.Effect<number>;
|
|
110
|
+
}
|
|
111
|
+
declare const EventBus_base: Context.TagClass<EventBus, "@harpoon/EventBus", EventBusService>;
|
|
112
|
+
/**
|
|
113
|
+
* EventBus service tag for dependency injection.
|
|
114
|
+
*/
|
|
115
|
+
export declare class EventBus extends EventBus_base {
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Live implementation using Effect PubSub.
|
|
119
|
+
*/
|
|
120
|
+
export declare const EventBusLive: Layer.Layer<EventBus, never, never>;
|
|
121
|
+
/**
|
|
122
|
+
* Test implementation that collects all events for verification.
|
|
123
|
+
*/
|
|
124
|
+
export declare const EventBusTest: Layer.Layer<EventBus, never, never>;
|
|
125
|
+
export {};
|
|
126
|
+
//# sourceMappingURL=EventBus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventBus.d.ts","sourceRoot":"","sources":["../../src/services/EventBus.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EventBus Service
|
|
3
|
+
*
|
|
4
|
+
* Provides a publish/subscribe event system for Harpoon resource lifecycle events.
|
|
5
|
+
* Uses Effect's PubSub for type-safe, concurrent event distribution.
|
|
6
|
+
*/
|
|
7
|
+
import { Context, Effect, Layer, PubSub, Stream } from 'effect';
|
|
8
|
+
// ============ Event Constructors ============
|
|
9
|
+
/**
|
|
10
|
+
* Create a container event.
|
|
11
|
+
*/
|
|
12
|
+
export const containerEvent = (type, containerId, containerName, options) => ({
|
|
13
|
+
_tag: 'ContainerEvent',
|
|
14
|
+
type,
|
|
15
|
+
containerId,
|
|
16
|
+
containerName,
|
|
17
|
+
timestamp: new Date(),
|
|
18
|
+
...(options?.metadata !== undefined && { metadata: options.metadata }),
|
|
19
|
+
...(options?.error !== undefined && { error: options.error }),
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* Create a network event.
|
|
23
|
+
*/
|
|
24
|
+
export const networkEvent = (type, networkId, networkName, options) => ({
|
|
25
|
+
_tag: 'NetworkEvent',
|
|
26
|
+
type,
|
|
27
|
+
networkId,
|
|
28
|
+
networkName,
|
|
29
|
+
timestamp: new Date(),
|
|
30
|
+
...(options?.metadata !== undefined && { metadata: options.metadata }),
|
|
31
|
+
});
|
|
32
|
+
/**
|
|
33
|
+
* Create a database event.
|
|
34
|
+
*/
|
|
35
|
+
export const databaseEvent = (type, containerId, databaseName, databaseType, options) => ({
|
|
36
|
+
_tag: 'DatabaseEvent',
|
|
37
|
+
type,
|
|
38
|
+
containerId,
|
|
39
|
+
databaseName,
|
|
40
|
+
databaseType,
|
|
41
|
+
timestamp: new Date(),
|
|
42
|
+
...(options?.connectionString !== undefined && { connectionString: options.connectionString }),
|
|
43
|
+
...(options?.metadata !== undefined && { metadata: options.metadata }),
|
|
44
|
+
});
|
|
45
|
+
/**
|
|
46
|
+
* EventBus service tag for dependency injection.
|
|
47
|
+
*/
|
|
48
|
+
export class EventBus extends Context.Tag('@harpoon/EventBus')() {
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Live implementation using Effect PubSub.
|
|
52
|
+
*/
|
|
53
|
+
export const EventBusLive = Layer.scoped(EventBus, Effect.gen(function* () {
|
|
54
|
+
// Create an unbounded PubSub for events
|
|
55
|
+
const pubsub = yield* PubSub.unbounded();
|
|
56
|
+
yield* Effect.logDebug('EventBus initialized');
|
|
57
|
+
const service = {
|
|
58
|
+
_tag: 'EventBus',
|
|
59
|
+
publish: (event) => PubSub.publish(pubsub, event).pipe(Effect.tap(() => Effect.logDebug('Event published').pipe(Effect.annotateLogs({
|
|
60
|
+
eventTag: event._tag,
|
|
61
|
+
eventType: event._tag === 'ContainerEvent' || event._tag === 'DatabaseEvent'
|
|
62
|
+
? event.type
|
|
63
|
+
: event.type,
|
|
64
|
+
})))),
|
|
65
|
+
subscribe: () => Effect.gen(function* () {
|
|
66
|
+
const queue = yield* PubSub.subscribe(pubsub);
|
|
67
|
+
return Stream.fromQueue(queue);
|
|
68
|
+
}),
|
|
69
|
+
subscribeContainers: () => Effect.gen(function* () {
|
|
70
|
+
const queue = yield* PubSub.subscribe(pubsub);
|
|
71
|
+
return Stream.fromQueue(queue).pipe(Stream.filter((event) => event._tag === 'ContainerEvent'));
|
|
72
|
+
}),
|
|
73
|
+
subscribeNetworks: () => Effect.gen(function* () {
|
|
74
|
+
const queue = yield* PubSub.subscribe(pubsub);
|
|
75
|
+
return Stream.fromQueue(queue).pipe(Stream.filter((event) => event._tag === 'NetworkEvent'));
|
|
76
|
+
}),
|
|
77
|
+
subscribeDatabases: () => Effect.gen(function* () {
|
|
78
|
+
const queue = yield* PubSub.subscribe(pubsub);
|
|
79
|
+
return Stream.fromQueue(queue).pipe(Stream.filter((event) => event._tag === 'DatabaseEvent'));
|
|
80
|
+
}),
|
|
81
|
+
subscriberCount: () => PubSub.size(pubsub),
|
|
82
|
+
};
|
|
83
|
+
return service;
|
|
84
|
+
}));
|
|
85
|
+
/**
|
|
86
|
+
* Test implementation that collects all events for verification.
|
|
87
|
+
*/
|
|
88
|
+
export const EventBusTest = Layer.scoped(EventBus, Effect.gen(function* () {
|
|
89
|
+
const pubsub = yield* PubSub.unbounded();
|
|
90
|
+
return {
|
|
91
|
+
_tag: 'EventBus',
|
|
92
|
+
publish: (event) => PubSub.publish(pubsub, event),
|
|
93
|
+
subscribe: () => Effect.gen(function* () {
|
|
94
|
+
const queue = yield* PubSub.subscribe(pubsub);
|
|
95
|
+
return Stream.fromQueue(queue);
|
|
96
|
+
}),
|
|
97
|
+
subscribeContainers: () => Effect.gen(function* () {
|
|
98
|
+
const queue = yield* PubSub.subscribe(pubsub);
|
|
99
|
+
return Stream.fromQueue(queue).pipe(Stream.filter((event) => event._tag === 'ContainerEvent'));
|
|
100
|
+
}),
|
|
101
|
+
subscribeNetworks: () => Effect.gen(function* () {
|
|
102
|
+
const queue = yield* PubSub.subscribe(pubsub);
|
|
103
|
+
return Stream.fromQueue(queue).pipe(Stream.filter((event) => event._tag === 'NetworkEvent'));
|
|
104
|
+
}),
|
|
105
|
+
subscribeDatabases: () => Effect.gen(function* () {
|
|
106
|
+
const queue = yield* PubSub.subscribe(pubsub);
|
|
107
|
+
return Stream.fromQueue(queue).pipe(Stream.filter((event) => event._tag === 'DatabaseEvent'));
|
|
108
|
+
}),
|
|
109
|
+
subscriberCount: () => PubSub.size(pubsub),
|
|
110
|
+
};
|
|
111
|
+
}));
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Harpoon Unified Layer
|
|
3
|
+
*
|
|
4
|
+
* Provides pre-composed layers for all Harpoon services.
|
|
5
|
+
* Makes it easy to use Harpoon with a single layer provision.
|
|
6
|
+
*/
|
|
7
|
+
import { Layer } from 'effect';
|
|
8
|
+
import { HarpoonConfig } from './HarpoonConfig';
|
|
9
|
+
import { DockerRateLimiter } from './DockerRateLimiter';
|
|
10
|
+
import { CircuitBreaker } from './CircuitBreaker';
|
|
11
|
+
import { DockerClient } from './DockerClient';
|
|
12
|
+
import { DockerBatcher } from './DockerBatcher';
|
|
13
|
+
import { ResourceTracker } from './ResourceTracker';
|
|
14
|
+
import { EventBus } from './EventBus';
|
|
15
|
+
import { ReadinessCoordinator } from './ReadinessCoordinator';
|
|
16
|
+
/**
|
|
17
|
+
* Core configuration layer.
|
|
18
|
+
* Provides HarpoonConfig.
|
|
19
|
+
*/
|
|
20
|
+
export declare const CoreLive: Layer.Layer<HarpoonConfig, import("effect/ConfigError").ConfigError, never>;
|
|
21
|
+
/**
|
|
22
|
+
* Infrastructure layer with rate limiting and circuit breaker.
|
|
23
|
+
* Provides: DockerRateLimiter, CircuitBreaker
|
|
24
|
+
* Requires: HarpoonConfig
|
|
25
|
+
*/
|
|
26
|
+
export declare const InfrastructureLive: Layer.Layer<CircuitBreaker | DockerRateLimiter, import("effect/ConfigError").ConfigError, never>;
|
|
27
|
+
/**
|
|
28
|
+
* Docker client layer with all integrations.
|
|
29
|
+
* Provides: DockerClient
|
|
30
|
+
* Requires: HarpoonConfig, DockerRateLimiter
|
|
31
|
+
*/
|
|
32
|
+
export declare const DockerLive: Layer.Layer<DockerClient, import("./DockerErrors").DockerConnectionError | import("effect/ConfigError").ConfigError, never>;
|
|
33
|
+
/**
|
|
34
|
+
* Batching layer for Docker requests.
|
|
35
|
+
* Provides: DockerBatcher
|
|
36
|
+
* Requires: DockerClient
|
|
37
|
+
*/
|
|
38
|
+
export declare const BatcherLive: Layer.Layer<DockerBatcher, import("./DockerErrors").DockerConnectionError | import("effect/ConfigError").ConfigError, never>;
|
|
39
|
+
/**
|
|
40
|
+
* Resource management layer.
|
|
41
|
+
* Provides: ResourceTracker
|
|
42
|
+
* Requires: HarpoonConfig
|
|
43
|
+
*/
|
|
44
|
+
export declare const ResourcesLive: Layer.Layer<ResourceTracker, import("effect/ConfigError").ConfigError, never>;
|
|
45
|
+
/**
|
|
46
|
+
* Event bus layer.
|
|
47
|
+
* Provides: EventBus
|
|
48
|
+
*/
|
|
49
|
+
export declare const EventsLive: Layer.Layer<EventBus, never, never>;
|
|
50
|
+
/**
|
|
51
|
+
* Readiness coordination layer.
|
|
52
|
+
* Provides: ReadinessCoordinator
|
|
53
|
+
*/
|
|
54
|
+
export declare const ReadinessLive: Layer.Layer<ReadinessCoordinator, never, never>;
|
|
55
|
+
/**
|
|
56
|
+
* Services layer combining all coordination services.
|
|
57
|
+
* Provides: ResourceTracker, EventBus, ReadinessCoordinator
|
|
58
|
+
* Requires: HarpoonConfig
|
|
59
|
+
*/
|
|
60
|
+
export declare const ServicesLive: Layer.Layer<EventBus | ReadinessCoordinator | ResourceTracker, import("effect/ConfigError").ConfigError, never>;
|
|
61
|
+
/**
|
|
62
|
+
* Full Harpoon layer for production use.
|
|
63
|
+
* Provides all services needed for Docker resource management.
|
|
64
|
+
*
|
|
65
|
+
* Includes:
|
|
66
|
+
* - HarpoonConfig
|
|
67
|
+
* - DockerRateLimiter
|
|
68
|
+
* - CircuitBreaker
|
|
69
|
+
* - DockerClient
|
|
70
|
+
* - DockerBatcher
|
|
71
|
+
* - ResourceTracker
|
|
72
|
+
* - EventBus
|
|
73
|
+
* - ReadinessCoordinator
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* import { HarpoonLive } from '@docker-harpoon/core/services';
|
|
78
|
+
*
|
|
79
|
+
* const program = Effect.gen(function* () {
|
|
80
|
+
* const docker = yield* DockerClient;
|
|
81
|
+
* const tracker = yield* ResourceTracker;
|
|
82
|
+
* // ... use services
|
|
83
|
+
* });
|
|
84
|
+
*
|
|
85
|
+
* Effect.runPromise(
|
|
86
|
+
* program.pipe(Effect.provide(HarpoonLive))
|
|
87
|
+
* );
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export declare const HarpoonLive: Layer.Layer<CircuitBreaker | DockerBatcher | DockerClient | DockerRateLimiter | EventBus | HarpoonConfig | ReadinessCoordinator | ResourceTracker, import("./DockerErrors").DockerConnectionError | import("effect/ConfigError").ConfigError, never>;
|
|
91
|
+
/**
|
|
92
|
+
* Core test configuration layer.
|
|
93
|
+
*/
|
|
94
|
+
export declare const CoreTest: Layer.Layer<HarpoonConfig, never, never>;
|
|
95
|
+
/**
|
|
96
|
+
* Infrastructure test layer.
|
|
97
|
+
*/
|
|
98
|
+
export declare const InfrastructureTest: Layer.Layer<CircuitBreaker | DockerRateLimiter, never, never>;
|
|
99
|
+
/**
|
|
100
|
+
* Docker client test layer.
|
|
101
|
+
*/
|
|
102
|
+
export declare const DockerTest: Layer.Layer<DockerClient, never, never>;
|
|
103
|
+
/**
|
|
104
|
+
* Batcher test layer.
|
|
105
|
+
*/
|
|
106
|
+
export declare const BatcherTest: Layer.Layer<DockerBatcher, never, never>;
|
|
107
|
+
/**
|
|
108
|
+
* Resources test layer.
|
|
109
|
+
*/
|
|
110
|
+
export declare const ResourcesTest: Layer.Layer<ResourceTracker, never, never>;
|
|
111
|
+
/**
|
|
112
|
+
* Events test layer.
|
|
113
|
+
*/
|
|
114
|
+
export declare const EventsTest: Layer.Layer<EventBus, never, never>;
|
|
115
|
+
/**
|
|
116
|
+
* Readiness test layer.
|
|
117
|
+
*/
|
|
118
|
+
export declare const ReadinessTest: Layer.Layer<ReadinessCoordinator, never, never>;
|
|
119
|
+
/**
|
|
120
|
+
* Services test layer.
|
|
121
|
+
*/
|
|
122
|
+
export declare const ServicesTest: Layer.Layer<EventBus | ReadinessCoordinator | ResourceTracker, never, never>;
|
|
123
|
+
/**
|
|
124
|
+
* Full Harpoon test layer for unit testing.
|
|
125
|
+
* All services use mock implementations that don't require Docker.
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```typescript
|
|
129
|
+
* import { HarpoonTest } from '@docker-harpoon/core/services';
|
|
130
|
+
*
|
|
131
|
+
* const test = Effect.gen(function* () {
|
|
132
|
+
* const docker = yield* DockerClient;
|
|
133
|
+
* // Uses mock Docker client
|
|
134
|
+
* });
|
|
135
|
+
*
|
|
136
|
+
* Effect.runPromise(
|
|
137
|
+
* test.pipe(Effect.provide(HarpoonTest))
|
|
138
|
+
* );
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
export declare const HarpoonTest: Layer.Layer<CircuitBreaker | DockerBatcher | DockerClient | DockerRateLimiter | EventBus | HarpoonConfig | ReadinessCoordinator | ResourceTracker, never, never>;
|
|
142
|
+
/**
|
|
143
|
+
* All services provided by HarpoonLive.
|
|
144
|
+
*/
|
|
145
|
+
export type HarpoonServices = HarpoonConfig | DockerRateLimiter | CircuitBreaker | DockerClient | DockerBatcher | ResourceTracker | EventBus | ReadinessCoordinator;
|
|
146
|
+
/**
|
|
147
|
+
* Requirements for running a program with Harpoon.
|
|
148
|
+
* Use with Effect.provide(HarpoonLive) to satisfy.
|
|
149
|
+
*/
|
|
150
|
+
export type HarpoonRequirements = HarpoonServices;
|
|
151
|
+
//# sourceMappingURL=Harpoon.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Harpoon.d.ts","sourceRoot":"","sources":["../../src/services/Harpoon.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,EAAU,MAAM,QAAQ,CAAC;AAGvC,OAAO,EAAE,aAAa,EAAwC,MAAM,iBAAiB,CAAC;AAItF,OAAO,EACL,iBAAiB,EAGlB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,cAAc,EAA0C,MAAM,kBAAkB,CAAC;AAG1F,OAAO,EAAE,YAAY,EAAsC,MAAM,gBAAgB,CAAC;AAClF,OAAO,EAAE,aAAa,EAAwC,MAAM,iBAAiB,CAAC;AAGtF,OAAO,EAAE,eAAe,EAA4C,MAAM,mBAAmB,CAAC;AAG9F,OAAO,EAAE,QAAQ,EAA8B,MAAM,YAAY,CAAC;AAClE,OAAO,EACL,oBAAoB,EAGrB,MAAM,wBAAwB,CAAC;AAIhC;;;GAGG;AACH,eAAO,MAAM,QAAQ,6EAAoB,CAAC;AAE1C;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,kGAE9B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,UAAU,6HAAiD,CAAC;AAEzE;;;;GAIG;AACH,eAAO,MAAM,WAAW,8HAAoD,CAAC;AAE7E;;;;GAIG;AACH,eAAO,MAAM,aAAa,+EAAoD,CAAC;AAE/E;;;GAGG;AACH,eAAO,MAAM,UAAU,qCAAe,CAAC;AAEvC;;;GAGG;AACH,eAAO,MAAM,aAAa,iDAA2B,CAAC;AAEtD;;;;GAIG;AACH,eAAO,MAAM,YAAY,iHAA2D,CAAC;AAErF;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,WAAW,sPAMvB,CAAC;AAIF;;GAEG;AACH,eAAO,MAAM,QAAQ,0CAAoB,CAAC;AAE1C;;GAEG;AACH,eAAO,MAAM,kBAAkB,+DAA4D,CAAC;AAE5F;;GAEG;AACH,eAAO,MAAM,UAAU,yCAAmB,CAAC;AAE3C;;GAEG;AACH,eAAO,MAAM,WAAW,0CAAoD,CAAC;AAE7E;;GAEG;AACH,eAAO,MAAM,aAAa,4CAAsB,CAAC;AAEjD;;GAEG;AACH,eAAO,MAAM,UAAU,qCAAe,CAAC;AAEvC;;GAEG;AACH,eAAO,MAAM,aAAa,iDAA2B,CAAC;AAEtD;;GAEG;AACH,eAAO,MAAM,YAAY,8EAA2D,CAAC;AAErF;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,WAAW,kKAMvB,CAAC;AAIF;;GAEG;AACH,MAAM,MAAM,eAAe,GACvB,aAAa,GACb,iBAAiB,GACjB,cAAc,GACd,YAAY,GACZ,aAAa,GACb,eAAe,GACf,QAAQ,GACR,oBAAoB,CAAC;AAEzB;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,eAAe,CAAC"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Harpoon Unified Layer
|
|
3
|
+
*
|
|
4
|
+
* Provides pre-composed layers for all Harpoon services.
|
|
5
|
+
* Makes it easy to use Harpoon with a single layer provision.
|
|
6
|
+
*/
|
|
7
|
+
import { Layer } from 'effect';
|
|
8
|
+
// Core services
|
|
9
|
+
import { HarpoonConfigLive, HarpoonConfigTest } from './HarpoonConfig';
|
|
10
|
+
// Infrastructure services
|
|
11
|
+
import { DockerRateLimiterLive, DockerRateLimiterTest, } from './DockerRateLimiter';
|
|
12
|
+
import { CircuitBreakerLive, CircuitBreakerTest } from './CircuitBreaker';
|
|
13
|
+
// Docker services
|
|
14
|
+
import { DockerClientLive, DockerClientTest } from './DockerClient';
|
|
15
|
+
import { DockerBatcherLive, DockerBatcherTest } from './DockerBatcher';
|
|
16
|
+
// Resource management
|
|
17
|
+
import { ResourceTrackerLive, ResourceTrackerTest } from './ResourceTracker';
|
|
18
|
+
// Event and coordination
|
|
19
|
+
import { EventBusLive, EventBusTest } from './EventBus';
|
|
20
|
+
import { ReadinessCoordinatorLive, ReadinessCoordinatorTest, } from './ReadinessCoordinator';
|
|
21
|
+
// ============ Live Layers ============
|
|
22
|
+
/**
|
|
23
|
+
* Core configuration layer.
|
|
24
|
+
* Provides HarpoonConfig.
|
|
25
|
+
*/
|
|
26
|
+
export const CoreLive = HarpoonConfigLive;
|
|
27
|
+
/**
|
|
28
|
+
* Infrastructure layer with rate limiting and circuit breaker.
|
|
29
|
+
* Provides: DockerRateLimiter, CircuitBreaker
|
|
30
|
+
* Requires: HarpoonConfig
|
|
31
|
+
*/
|
|
32
|
+
export const InfrastructureLive = Layer.mergeAll(DockerRateLimiterLive, CircuitBreakerLive).pipe(Layer.provide(CoreLive));
|
|
33
|
+
/**
|
|
34
|
+
* Docker client layer with all integrations.
|
|
35
|
+
* Provides: DockerClient
|
|
36
|
+
* Requires: HarpoonConfig, DockerRateLimiter
|
|
37
|
+
*/
|
|
38
|
+
export const DockerLive = DockerClientLive.pipe(Layer.provide(CoreLive));
|
|
39
|
+
/**
|
|
40
|
+
* Batching layer for Docker requests.
|
|
41
|
+
* Provides: DockerBatcher
|
|
42
|
+
* Requires: DockerClient
|
|
43
|
+
*/
|
|
44
|
+
export const BatcherLive = DockerBatcherLive.pipe(Layer.provide(DockerLive));
|
|
45
|
+
/**
|
|
46
|
+
* Resource management layer.
|
|
47
|
+
* Provides: ResourceTracker
|
|
48
|
+
* Requires: HarpoonConfig
|
|
49
|
+
*/
|
|
50
|
+
export const ResourcesLive = ResourceTrackerLive.pipe(Layer.provide(CoreLive));
|
|
51
|
+
/**
|
|
52
|
+
* Event bus layer.
|
|
53
|
+
* Provides: EventBus
|
|
54
|
+
*/
|
|
55
|
+
export const EventsLive = EventBusLive;
|
|
56
|
+
/**
|
|
57
|
+
* Readiness coordination layer.
|
|
58
|
+
* Provides: ReadinessCoordinator
|
|
59
|
+
*/
|
|
60
|
+
export const ReadinessLive = ReadinessCoordinatorLive;
|
|
61
|
+
/**
|
|
62
|
+
* Services layer combining all coordination services.
|
|
63
|
+
* Provides: ResourceTracker, EventBus, ReadinessCoordinator
|
|
64
|
+
* Requires: HarpoonConfig
|
|
65
|
+
*/
|
|
66
|
+
export const ServicesLive = Layer.mergeAll(ResourcesLive, EventsLive, ReadinessLive);
|
|
67
|
+
/**
|
|
68
|
+
* Full Harpoon layer for production use.
|
|
69
|
+
* Provides all services needed for Docker resource management.
|
|
70
|
+
*
|
|
71
|
+
* Includes:
|
|
72
|
+
* - HarpoonConfig
|
|
73
|
+
* - DockerRateLimiter
|
|
74
|
+
* - CircuitBreaker
|
|
75
|
+
* - DockerClient
|
|
76
|
+
* - DockerBatcher
|
|
77
|
+
* - ResourceTracker
|
|
78
|
+
* - EventBus
|
|
79
|
+
* - ReadinessCoordinator
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```typescript
|
|
83
|
+
* import { HarpoonLive } from '@docker-harpoon/core/services';
|
|
84
|
+
*
|
|
85
|
+
* const program = Effect.gen(function* () {
|
|
86
|
+
* const docker = yield* DockerClient;
|
|
87
|
+
* const tracker = yield* ResourceTracker;
|
|
88
|
+
* // ... use services
|
|
89
|
+
* });
|
|
90
|
+
*
|
|
91
|
+
* Effect.runPromise(
|
|
92
|
+
* program.pipe(Effect.provide(HarpoonLive))
|
|
93
|
+
* );
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export const HarpoonLive = Layer.mergeAll(CoreLive, InfrastructureLive, DockerLive, BatcherLive, ServicesLive);
|
|
97
|
+
// ============ Test Layers ============
|
|
98
|
+
/**
|
|
99
|
+
* Core test configuration layer.
|
|
100
|
+
*/
|
|
101
|
+
export const CoreTest = HarpoonConfigTest;
|
|
102
|
+
/**
|
|
103
|
+
* Infrastructure test layer.
|
|
104
|
+
*/
|
|
105
|
+
export const InfrastructureTest = Layer.mergeAll(DockerRateLimiterTest, CircuitBreakerTest);
|
|
106
|
+
/**
|
|
107
|
+
* Docker client test layer.
|
|
108
|
+
*/
|
|
109
|
+
export const DockerTest = DockerClientTest;
|
|
110
|
+
/**
|
|
111
|
+
* Batcher test layer.
|
|
112
|
+
*/
|
|
113
|
+
export const BatcherTest = DockerBatcherTest.pipe(Layer.provide(DockerTest));
|
|
114
|
+
/**
|
|
115
|
+
* Resources test layer.
|
|
116
|
+
*/
|
|
117
|
+
export const ResourcesTest = ResourceTrackerTest;
|
|
118
|
+
/**
|
|
119
|
+
* Events test layer.
|
|
120
|
+
*/
|
|
121
|
+
export const EventsTest = EventBusTest;
|
|
122
|
+
/**
|
|
123
|
+
* Readiness test layer.
|
|
124
|
+
*/
|
|
125
|
+
export const ReadinessTest = ReadinessCoordinatorTest;
|
|
126
|
+
/**
|
|
127
|
+
* Services test layer.
|
|
128
|
+
*/
|
|
129
|
+
export const ServicesTest = Layer.mergeAll(ResourcesTest, EventsTest, ReadinessTest);
|
|
130
|
+
/**
|
|
131
|
+
* Full Harpoon test layer for unit testing.
|
|
132
|
+
* All services use mock implementations that don't require Docker.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```typescript
|
|
136
|
+
* import { HarpoonTest } from '@docker-harpoon/core/services';
|
|
137
|
+
*
|
|
138
|
+
* const test = Effect.gen(function* () {
|
|
139
|
+
* const docker = yield* DockerClient;
|
|
140
|
+
* // Uses mock Docker client
|
|
141
|
+
* });
|
|
142
|
+
*
|
|
143
|
+
* Effect.runPromise(
|
|
144
|
+
* test.pipe(Effect.provide(HarpoonTest))
|
|
145
|
+
* );
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
export const HarpoonTest = Layer.mergeAll(CoreTest, InfrastructureTest, DockerTest, BatcherTest, ServicesTest);
|