Skip to content

Commit 0f34ddf

Browse files
authored
feat: add constraints check for job resource allocation (#1270)
* feat: add constraints check for job resource allocation * fix: test * fix: lint * fix: reinstall npm packages * fix: ts error * fix: update buffer types in key provider
1 parent 7cedcef commit 0f34ddf

6 files changed

Lines changed: 338 additions & 12 deletions

File tree

.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ export P2P_BOOTSTRAP_NODES=
6565
export P2P_FILTER_ANNOUNCED_ADDRESSES=
6666

6767
## compute
68+
# Example with cross-resource constraints (constraints are optional and backwards-compatible):
69+
# export DOCKER_COMPUTE_ENVIRONMENTS='[{"socketPath":"/var/run/docker.sock","storageExpiry":604800,"maxJobDuration":3600,"minJobDuration":60,"fees":{"1":[{"feeToken":"0x123","prices":[{"id":"cpu","price":1},{"id":"ram","price":0.1},{"id":"disk","price":0.01}]}]},"resources":[{"id":"cpu","total":8,"max":8,"min":1,"constraints":[{"id":"ram","min":1,"max":3},{"id":"disk","min":10,"max":100}]},{"id":"ram","total":32,"max":32,"min":1},{"id":"disk","total":500,"max":500,"min":10},{"id":"gpu","total":4,"max":4,"min":0,"constraints":[{"id":"ram","min":8,"max":32},{"id":"cpu","min":2,"max":4}]}]}]'
6870
export DOCKER_COMPUTE_ENVIRONMENTS=
6971

7072

src/@types/C2D/C2D.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ export interface C2DClusterInfo {
2222

2323
export type ComputeResourceType = 'cpu' | 'ram' | 'disk' | any
2424

25+
export interface ResourceConstraint {
26+
id: ComputeResourceType // the resource being constrained
27+
min?: number // min units of this resource per unit of parent resource
28+
max?: number // max units of this resource per unit of parent resource
29+
}
30+
2531
export interface ComputeResourcesPricingInfo {
2632
id: ComputeResourceType
2733
price: number // price per unit per minute
@@ -63,6 +69,7 @@ export interface ComputeResource {
6369
*/
6470
platform?: string
6571
init?: dockerHwInit
72+
constraints?: ResourceConstraint[] // optional cross-resource constraints
6673
}
6774
export interface ComputeResourceRequest {
6875
id: string

src/components/c2d/compute_engine_base.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,9 +248,65 @@ export abstract class C2DEngine {
248248
properResources.push({ id: device, amount: desired })
249249
}
250250

251+
this.checkResourceConstraints(properResources, env, isFree)
251252
return properResources
252253
}
253254

255+
protected checkResourceConstraints(
256+
resources: ComputeResourceRequest[],
257+
env: ComputeEnvironment,
258+
isFree: boolean
259+
): void {
260+
const envResources = isFree ? (env.free?.resources ?? []) : (env.resources ?? [])
261+
for (const envResource of envResources) {
262+
if (!envResource.constraints || envResource.constraints.length === 0) continue
263+
const parentAmount = this.getResourceRequest(resources, envResource.id)
264+
if (!parentAmount || parentAmount <= 0) continue
265+
266+
for (const constraint of envResource.constraints) {
267+
let constrainedAmount = this.getResourceRequest(resources, constraint.id) ?? 0
268+
269+
if (constraint.min !== undefined) {
270+
const requiredMin = parentAmount * constraint.min
271+
if (constrainedAmount < requiredMin) {
272+
const constrainedMaxMin = this.getMaxMinResource(constraint.id, env, isFree)
273+
if (requiredMin > constrainedMaxMin.max) {
274+
throw new Error(
275+
`Cannot satisfy constraint: ${parentAmount} ${envResource.id} requires at least ${requiredMin} ${constraint.id}, but max is ${constrainedMaxMin.max}`
276+
)
277+
}
278+
this.setResourceAmount(resources, constraint.id, requiredMin)
279+
constrainedAmount = requiredMin
280+
}
281+
}
282+
283+
if (constraint.max !== undefined) {
284+
const requiredMax = parentAmount * constraint.max
285+
// re-read in case it was bumped above
286+
constrainedAmount = this.getResourceRequest(resources, constraint.id) ?? 0
287+
if (constrainedAmount > requiredMax) {
288+
throw new Error(
289+
`Too much ${constraint.id} for ${parentAmount} ${envResource.id}. Max allowed: ${requiredMax}, requested: ${constrainedAmount}`
290+
)
291+
}
292+
}
293+
}
294+
}
295+
}
296+
297+
protected setResourceAmount(
298+
resources: ComputeResourceRequest[],
299+
id: ComputeResourceType,
300+
amount: number
301+
): void {
302+
for (const resource of resources) {
303+
if (resource.id === id) {
304+
resource.amount = amount
305+
return
306+
}
307+
}
308+
}
309+
254310
public async getUsedResources(env: ComputeEnvironment): Promise<any> {
255311
const usedResources: { [x: string]: any } = {}
256312
const usedFreeResources: { [x: string]: any } = {}

src/test/integration/compute.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ describe('Compute', () => {
206206
oceanNode.blockchainRegistry
207207
)
208208
oceanNode.addIndexer(indexer)
209-
oceanNode.addC2DEngines()
209+
await oceanNode.addC2DEngines()
210210

211211
provider = new JsonRpcProvider('http://127.0.0.1:8545')
212212
publisherAccount = (await provider.getSigner(0)) as Signer
@@ -2216,7 +2216,7 @@ describe('Compute', () => {
22162216

22172217
after(async () => {
22182218
await tearDownEnvironment(previousConfiguration)
2219-
indexer.stopAllChainIndexers()
2219+
await indexer.stopAllChainIndexers()
22202220
})
22212221
})
22222222

@@ -2369,7 +2369,7 @@ describe('Compute Access Restrictions', () => {
23692369
oceanNode.blockchainRegistry
23702370
)
23712371
oceanNode.addIndexer(indexer)
2372-
oceanNode.addC2DEngines()
2372+
await oceanNode.addC2DEngines()
23732373

23742374
publishedComputeDataset = await publishAsset(computeAsset, publisherAccount)
23752375
publishedAlgoDataset = await publishAsset(algoAsset, publisherAccount)
@@ -2556,7 +2556,7 @@ describe('Compute Access Restrictions', () => {
25562556
oceanNode.blockchainRegistry
25572557
)
25582558
oceanNode.addIndexer(indexer)
2559-
oceanNode.addC2DEngines()
2559+
await oceanNode.addC2DEngines()
25602560

25612561
publishedComputeDataset = await publishAsset(computeAsset, publisherAccount)
25622562
publishedAlgoDataset = await publishAsset(algoAsset, publisherAccount)
@@ -2686,7 +2686,7 @@ describe('Compute Access Restrictions', () => {
26862686
oceanNode.blockchainRegistry
26872687
)
26882688
oceanNode.addIndexer(indexer)
2689-
oceanNode.addC2DEngines()
2689+
await oceanNode.addC2DEngines()
26902690

26912691
const provider = new JsonRpcProvider('http://127.0.0.1:8545')
26922692
const publisherAccount = (await provider.getSigner(0)) as Signer

0 commit comments

Comments
 (0)