Skip to content

Commit

Permalink
feat(ur): enable config to route From-Module
Browse files Browse the repository at this point in the history
  • Loading branch information
twilson63 committed Jan 18, 2025
1 parent d3562c5 commit 5a9b31a
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 3 deletions.
5 changes: 4 additions & 1 deletion servers/ur/src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const serverConfigSchema = z.object({
}, z.number().positive()),
processToHost: stringifiedJsonSchema.nullish(),
ownerToHost: stringifiedJsonSchema.nullish(),
fromModuleToHost: stringifiedJsonSchema.nullish(),
hosts: z.preprocess(
(arg) => (typeof arg === 'string' ? arg.split(',').map(str => str.trim()) : arg),
z.array(z.string().url())
Expand Down Expand Up @@ -68,6 +69,7 @@ const CONFIG_ENVS = {
hosts: process.env.HOSTS || ['http://127.0.0.1:3005'],
processToHost: process.env.PROCESS_TO_HOST || JSON.stringify({}),
ownerToHost: process.env.OWNER_TO_HOST || JSON.stringify({}),
fromModuleToHost: process.env.FROM_MODULE_TO_HOST || JSON.stringify({}),

/**
* default to the CU for no hassle startup in development mode,
Expand Down Expand Up @@ -95,7 +97,8 @@ const CONFIG_ENVS = {
hosts: process.env.HOSTS,
processToHost: process.env.PROCESS_TO_HOST || JSON.stringify({}),
ownerToHost: process.env.OWNER_TO_HOST || JSON.stringify({}),

fromModuleToHost: process.env.FROM_MODULE_TO_HOST || JSON.stringify({}),

aoUnit: process.env.AO_UNIT,
strategy: process.env.STRATEGY || 'proxy',

Expand Down
43 changes: 41 additions & 2 deletions servers/ur/src/domain.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { defaultTo, isEmpty, complement, path } from 'ramda'
import { defaultTo, isEmpty, complement, path, propEq } from 'ramda'
import { LRUCache } from 'lru-cache'

const isNotEmpty = complement(isEmpty)

export function bailoutWith ({ fetch, subrouterUrl, surUrl, owners, processToHost, ownerToHost }) {
export function bailoutWith ({ fetch, subrouterUrl, surUrl, owners, processToHost, ownerToHost, fromModuleToHost }) {
const processToOwnerCache = new LRUCache({
/**
* 10MB
Expand All @@ -15,6 +15,17 @@ export function bailoutWith ({ fetch, subrouterUrl, surUrl, owners, processToHos
sizeCalculation: () => 8
})

const fromModuleCache = new LRUCache({
/**
* 10MB
*/
maxSize: 10_000_000,
/**
* A number is 8 bytes
*/
sizeCalculation: () => 8
})

async function findProcessOwner (processId) {
const owner = processToOwnerCache.get(processId)
if (owner) return owner
Expand All @@ -32,6 +43,25 @@ export function bailoutWith ({ fetch, subrouterUrl, surUrl, owners, processToHos
.catch((_e) => null)
}

async function findFromModule (processId) {
const module = fromModuleCache.get(processId)
if (module) return module

return fetch(`${surUrl}/processes/${processId}`)
.then((res) => res.json())
.then(defaultTo({}))
.then(p => {
return p.tags.find(propEq('From-Module', 'name'))?.value
})
.then((module) => {
if (!module) return null

fromModuleCache.set(processId, module)
return module
})
.catch((_e) => null)
}

return async (processId) => {
/**
* If a process has a specific mapping configured,
Expand All @@ -47,6 +77,15 @@ export function bailoutWith ({ fetch, subrouterUrl, surUrl, owners, processToHos
if (ownerToHost[owner]) return ownerToHost[owner]
}

/**
* If there are fromModule -> host configured, then we lookup the
* from-module and return the specific host if found
*/
if (fromModuleToHost && isNotEmpty(fromModuleToHost)) {
const module = await findFromModule(processId)
if (fromModuleToHost[module]) return fromModuleToHost[module]
}

/**
* @deprecated - this functionality is subsumed by ownerToHost
* and will eventually be removed
Expand Down
68 changes: 68 additions & 0 deletions servers/ur/src/domain.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,74 @@ describe('domain', () => {
})
})

describe('fromModuleToHost', () => {
test('should bailout if the process fromModule is mapped to a specific host', async () => {
const fetchMock = async (url) => {
assert.equal(url, 'surUrl1/processes/process-123')
return new Response(JSON.stringify({ owner: { address: 'owner2' }, tags: [{name:'From-Module', value: 'fromModule1'}] }))
}

const bailout = bailoutWith({
fetch: fetchMock,
surUrl: 'surUrl1',
fromModuleToHost: { fromModule1: 'https://specific_owner.host' }
})

const determineHost = determineHostWith({ hosts: HOSTS, bailout })

const host = await determineHost({ processId: 'process-123', failoverAttempt: 0 })
assert.equal(host, 'https://specific_owner.host')
})

test('should NOT bailout if the process owner is not mapped to a specific host', async () => {
const fetchMock = async (url) => {
assert.equal(url, 'surUrl1/processes/process-123')
return new Response(JSON.stringify({ owner: { address: 'owner2' }, tags: [{name:'From-Module', value: 'fromModule1'}] }))
}

const bailout = bailoutWith({
fetch: fetchMock,
surUrl: 'surUrl1',
fromModuleToHost: { notFromModule1: 'https://specific_owner.host' }
})

const determineHost = determineHostWith({ hosts: HOSTS, bailout })

const host = await determineHost({ processId: 'process-123', failoverAttempt: 0 })
assert.ok(host !== 'https://specific_owner.host')
assert.ok(HOSTS.includes(host))
})

test('should NOT bailout if no fromModuleToHost is provided', async () => {
const fetchMock = async (url) => {
assert.equal(url, 'surUrl1/processes/process-123')
return new Response(JSON.stringify({ owner: { address: 'owner2' }, tags: [{name:'From-Module', value: 'fromModule1'}] }))
}

const determineHostEmptyMapping = determineHostWith({
hosts: HOSTS,
bailout: bailoutWith({
fetch: fetchMock,
surUrl: 'surUrl1',
fromModuleToHost: {}
})
})
const host = await determineHostEmptyMapping({ processId: 'process-123', failoverAttempt: 0 })
assert.ok(HOSTS.includes(host))

const determineHostNoMapping = determineHostWith({
hosts: HOSTS,
bailout: bailoutWith({
fetch: fetchMock,
surUrl: 'surUrl1',
ownerToHost: undefined
})
})
const host1 = await determineHostNoMapping({ processId: 'process-123', failoverAttempt: 0 })
assert.ok(HOSTS.includes(host1))
})
})

describe('ownerToHost', () => {
test('should bailout if the process owner is mapped to a specific host', async () => {
const fetchMock = async (url) => {
Expand Down

0 comments on commit 5a9b31a

Please sign in to comment.