-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Implement BulkheadIsolationPolicy
Closes #199.
- Loading branch information
Showing
17 changed files
with
807 additions
and
181 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,27 @@ | ||
import { ExecutedFn } from '../types/executedFn'; | ||
import { PolicyModificationNotAllowedException } from '../types/policyModificationNotAllowedException'; | ||
|
||
export abstract class Policy<ResultType> { | ||
public abstract async execute(fn: () => ResultType | Promise<ResultType>): Promise<ResultType>; | ||
private executing = 0; | ||
|
||
public async execute(fn: ExecutedFn<ResultType>): Promise<ResultType> { | ||
try { | ||
this.executing++; | ||
return await this.policyExecutorImpl(fn); | ||
} finally { | ||
this.executing--; | ||
} | ||
} | ||
|
||
public isExecuting(): boolean { | ||
return this.executing > 0; | ||
} | ||
|
||
protected throwForPolicyModificationIfExecuting(): void { | ||
if (this.isExecuting()) { | ||
throw new PolicyModificationNotAllowedException(); | ||
} | ||
} | ||
|
||
protected abstract async policyExecutorImpl(fn: ExecutedFn<ResultType>): Promise<ResultType>; | ||
} |
1 change: 1 addition & 0 deletions
1
src/policies/proactive/bulkheadIsolationPolicy/bulkheadCompartmentRejectedException.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export class BulkheadCompartmentRejectedException extends Error {} |
75 changes: 75 additions & 0 deletions
75
src/policies/proactive/bulkheadIsolationPolicy/bulkheadIsolationPolicy.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { SuccessDeferred } from '../../../utils/successDeferred'; | ||
import { ProactivePolicy } from '../proactivePolicy'; | ||
import { BulkheadCompartmentRejectedException } from './bulkheadCompartmentRejectedException'; | ||
|
||
export class BulkheadIsolationPolicy<ResultType> extends ProactivePolicy<ResultType> { | ||
private bulkheadCompartmentSize = Number.POSITIVE_INFINITY; | ||
private queueSize = 0; | ||
|
||
private bulkheadCompartmentUsage = 0; | ||
private readonly queue: Array<SuccessDeferred<void>> = []; | ||
|
||
public maxConcurrency(bulkheadCompartmentSize: number): void { | ||
if (!Number.isInteger(bulkheadCompartmentSize)) { | ||
throw new Error('bulkheadCompartmentSize must be integer'); | ||
} | ||
|
||
if (bulkheadCompartmentSize <= 0) { | ||
throw new Error('bulkheadCompartmentSize must be greater than 0'); | ||
} | ||
|
||
if (!Number.isSafeInteger(bulkheadCompartmentSize)) { | ||
throw new Error('bulkheadCompartmentSize must be less than or equal to 2^53 - 1'); | ||
} | ||
|
||
this.throwForPolicyModificationIfExecuting(); | ||
|
||
this.bulkheadCompartmentSize = bulkheadCompartmentSize; | ||
} | ||
|
||
public maxQueuedActions(queueSize: number): void { | ||
if (!Number.isInteger(queueSize)) { | ||
throw new Error('queueSize must be integer'); | ||
} | ||
|
||
if (queueSize < 0) { | ||
throw new Error('queueSize must be greater than or equal to 0'); | ||
} | ||
|
||
if (!Number.isSafeInteger(queueSize)) { | ||
throw new Error('queueSize must be less than or equal to 2^53 - 1'); | ||
} | ||
|
||
this.throwForPolicyModificationIfExecuting(); | ||
|
||
this.queueSize = queueSize; | ||
} | ||
|
||
public getAvailableSlotsCount(): number { | ||
return this.bulkheadCompartmentSize - this.bulkheadCompartmentUsage; | ||
} | ||
|
||
public getAvailableQueuedActionsCount(): number { | ||
return this.queueSize - this.queue.length; | ||
} | ||
|
||
protected async policyExecutorImpl(fn: () => ResultType | Promise<ResultType>): Promise<ResultType> { | ||
if (this.bulkheadCompartmentUsage >= this.bulkheadCompartmentSize) { | ||
if (this.queue.length >= this.queueSize) { | ||
throw new BulkheadCompartmentRejectedException(); | ||
} | ||
|
||
const queuingDeferred = new SuccessDeferred<void>(); | ||
this.queue.push(queuingDeferred); | ||
await queuingDeferred.promise; | ||
} | ||
|
||
try { | ||
this.bulkheadCompartmentUsage++; | ||
return await fn(); | ||
} finally { | ||
this.bulkheadCompartmentUsage--; | ||
this.queue.shift()?.resolve(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.