mirror of
https://github.com/pockethost/pockethost.git
synced 2025-05-30 10:46:39 +00:00
enh: port pooling
This commit is contained in:
parent
eb8bed9cea
commit
91cbc91c2a
@ -1,7 +1,6 @@
|
||||
import {
|
||||
DAEMON_PB_DATA_DIR,
|
||||
DAEMON_PB_IDLE_TTL,
|
||||
DAEMON_PB_PORT_BASE,
|
||||
PUBLIC_APP_DB,
|
||||
PUBLIC_APP_DOMAIN,
|
||||
PUBLIC_APP_PROTOCOL,
|
||||
@ -22,16 +21,16 @@ import {
|
||||
SingletonBaseConfig,
|
||||
StreamNames,
|
||||
} from '@pockethost/common'
|
||||
import { map, remove, values } from '@s-libs/micro-dash'
|
||||
import { map, values } from '@s-libs/micro-dash'
|
||||
import Bottleneck from 'bottleneck'
|
||||
import { existsSync } from 'fs'
|
||||
import getPort from 'get-port'
|
||||
import { join } from 'path'
|
||||
import { ClientResponseError } from 'pocketbase'
|
||||
import { AsyncReturnType } from 'type-fest'
|
||||
import { instanceLoggerService } from '../InstanceLoggerService'
|
||||
import { pocketbase } from '../PocketBaseService'
|
||||
import { createDenoProcess } from './Deno/DenoProcess'
|
||||
import { portManager } from './PortManager'
|
||||
|
||||
enum InstanceApiStatus {
|
||||
Starting = 'starting',
|
||||
@ -206,7 +205,7 @@ export const instanceService = mkSingleton(
|
||||
healthyGuard()
|
||||
await updateInstanceStatus(instance.id, InstanceStatus.Port)
|
||||
healthyGuard()
|
||||
const [newPort, releasePort] = await getNextPort()
|
||||
const [newPort, releasePort] = getNextPort()
|
||||
shutdownManager.add(() => {
|
||||
dbg(`Releasing port`)
|
||||
releasePort()
|
||||
@ -508,37 +507,7 @@ export const instanceService = mkSingleton(
|
||||
`InstanceService`
|
||||
)
|
||||
|
||||
const getNextPort = (() => {
|
||||
const { dbg } = instanceServiceLogger.create(`getNextPort`)
|
||||
let exclude: number[] = []
|
||||
|
||||
return serialAsyncExecutionGuard(
|
||||
async (): Promise<[number, () => void]> => {
|
||||
dbg(`Getting free port`)
|
||||
try {
|
||||
const newPort = await getPort({
|
||||
port: DAEMON_PB_PORT_BASE,
|
||||
exclude,
|
||||
})
|
||||
exclude.push(newPort)
|
||||
dbg(`Currently excluded ports: ${exclude.join(',')}`)
|
||||
return [
|
||||
newPort,
|
||||
() => {
|
||||
const removed = remove(exclude, (v) => v === newPort)
|
||||
dbg(
|
||||
`Removed ${removed.join(
|
||||
','
|
||||
)} from excluded ports: ${exclude.join(',')}`
|
||||
)
|
||||
},
|
||||
]
|
||||
} catch (e) {
|
||||
throw new Error(`Failed to get free port with ${e}`)
|
||||
}
|
||||
}
|
||||
)
|
||||
})()
|
||||
const { getNextPort } = await portManager({})
|
||||
|
||||
const shutdown = async () => {
|
||||
dbg(`Shutting down instance manager`)
|
||||
|
62
packages/daemon/src/services/InstanceService/PortManager.ts
Normal file
62
packages/daemon/src/services/InstanceService/PortManager.ts
Normal file
@ -0,0 +1,62 @@
|
||||
import { DAEMON_PB_PORT_BASE } from '$constants'
|
||||
import { serialAsyncExecutionGuard } from '$src/util/serialAsyncExecutionGuard'
|
||||
import { logger, mkSingleton } from '@pockethost/common'
|
||||
import { range, remove } from '@s-libs/micro-dash'
|
||||
import getPort from 'get-port'
|
||||
|
||||
export type PortResult = [number, () => void]
|
||||
|
||||
export const portManager = mkSingleton(async () => {
|
||||
const _logger = logger().create(`PortManager`)
|
||||
const { dbg, error } = _logger
|
||||
|
||||
const getNextPort = (() => {
|
||||
const { dbg, error } = _logger.create(`getNextPort`)
|
||||
let exclude: number[] = []
|
||||
|
||||
return serialAsyncExecutionGuard(async (): Promise<PortResult> => {
|
||||
dbg(`Getting free port`)
|
||||
try {
|
||||
const newPort = await getPort({
|
||||
port: DAEMON_PB_PORT_BASE,
|
||||
exclude,
|
||||
})
|
||||
exclude.push(newPort)
|
||||
dbg(`Currently excluded ports: ${exclude.join(',')}`)
|
||||
return [
|
||||
newPort,
|
||||
() => {
|
||||
const removed = remove(exclude, (v) => v === newPort)
|
||||
dbg(
|
||||
`Removed ${removed.join(',')} from excluded ports: ${exclude.join(
|
||||
','
|
||||
)}`
|
||||
)
|
||||
},
|
||||
]
|
||||
} catch (e) {
|
||||
throw new Error(`Failed to get free port with ${e}`)
|
||||
}
|
||||
})
|
||||
})()
|
||||
|
||||
const ports = await (
|
||||
await Promise.all<PortResult>(range(500).map(getNextPort))
|
||||
).map((portInfo) => portInfo[0])
|
||||
|
||||
return {
|
||||
getNextPort: (): PortResult => {
|
||||
const port = ports.pop()
|
||||
if (!port) {
|
||||
throw new Error(`Out of ports`)
|
||||
}
|
||||
return [
|
||||
port,
|
||||
() => {
|
||||
ports.push(port)
|
||||
},
|
||||
]
|
||||
},
|
||||
shutdown: () => {},
|
||||
}
|
||||
})
|
Loading…
x
Reference in New Issue
Block a user