Skip to content

Commit

Permalink
service: Expose server options as startup params
Browse files Browse the repository at this point in the history
- New startup parameters: 'body-size-limit', 'info-rate-limit',
'status-rate-limit'
  • Loading branch information
fordN committed May 31, 2024
1 parent ed0b25a commit fbc026d
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 35 deletions.
26 changes: 26 additions & 0 deletions packages/indexer-service/src/commands/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,29 @@ export default {
type: 'string',
required: false,
})
.option('info-rate-limit', {
description:
'Max requests per minute before returning 429 status codes, applies to paths: /cost, /subgraphs/health, /operator',
type: 'number',
required: false,
default: 300,
group: 'Server options',
})
.option('status-rate-limit', {
description:
'Max requests per minute before returning 429 status codes, applies to paths: /status, /network',
type: 'number',
required: false,
default: 300,
group: 'Server options',
})
.option('body-size-limit', {
description: 'Max body size per request (mb)',
type: 'number',
required: false,
default: 0.1,
group: 'Server options',
})

.check(argv => {
if (!argv['network-subgraph-endpoint'] && !argv['network-subgraph-deployment']) {
Expand Down Expand Up @@ -486,6 +509,9 @@ export default {
networkSubgraph,
networkSubgraphAuthToken: argv.networkSubgraphAuthToken,
serveNetworkSubgraph: argv.serveNetworkSubgraph,
infoRateLimit: argv.infoRateLimit,
statusRateLimit: argv.statusRateLimit,
bodySizeLimit: argv.bodySizeLimit,
})
},
}
85 changes: 50 additions & 35 deletions packages/indexer-service/src/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ export interface ServerOptions {
networkSubgraph: NetworkSubgraph
networkSubgraphAuthToken: string | undefined
serveNetworkSubgraph: boolean
infoRateLimit: number
statusRateLimit: number
bodySizeLimit: number
}

export const createApp = async ({
Expand All @@ -53,6 +56,9 @@ export const createApp = async ({
networkSubgraph,
networkSubgraphAuthToken,
serveNetworkSubgraph,
infoRateLimit,
statusRateLimit,
bodySizeLimit,
}: ServerOptions): Promise<express.Express> => {
// Install metrics for incoming queries
const serverMetrics = {
Expand Down Expand Up @@ -142,16 +148,24 @@ export const createApp = async ({

const app = express()

// Limit status requests to 9000/30min (5/s)
// Body parsers
const bodySizeLimitString = `${bodySizeLimit}mb`
const jsonParser = bodyParser.json({ limit: bodySizeLimitString })
const rawParser = bodyParser.raw({
limit: bodySizeLimitString,
type: 'application/json',
})

// Limit status requests
const slowLimiter = rateLimit({
windowMs: 30 * 60 * 1000, // 1 minutes
max: 9000,
windowMs: 60 * 1000, // 1 minute
max: infoRateLimit,
})

// Limit network requests to 90000/30min (50/s)
// Limit network requests per minute
const networkLimiter = rateLimit({
windowMs: 30 * 60 * 1000, // 1 minutes
max: 90000,
windowMs: 60 * 1000, // 1 minute
max: statusRateLimit,
})

// Log requests to the logger stream
Expand All @@ -176,7 +190,7 @@ export const createApp = async ({
app.use(
'/status',
networkLimiter,
bodyParser.json(),
jsonParser,
await createStatusServer({ graphNodeStatusEndpoint }),
)

Expand All @@ -191,15 +205,15 @@ export const createApp = async ({
app.use(
'/cost',
slowLimiter,
bodyParser.json(),
jsonParser,
await createCostServer({ indexerManagementClient, metrics }),
)

// Endpoint for operator information
app.use(
'/operator',
slowLimiter,
bodyParser.json(),
jsonParser,
await createOperatorServer({ operatorPublicKey }),
)

Expand All @@ -210,42 +224,37 @@ export const createApp = async ({

if (serveNetworkSubgraph) {
// Endpoint for network subgraph queries
app.post(
`/network`,
networkLimiter,
bodyParser.raw({ type: 'application/json' }),
async (req, res) => {
try {
logger.info(`Handle network subgraph query`)

let networkSubgraphAuthValue: string | undefined
if (networkSubgraphAuthToken) {
networkSubgraphAuthValue = `Bearer ${networkSubgraphAuthToken}`
}
app.post(`/network`, networkLimiter, rawParser, async (req, res) => {
try {
logger.info(`Handle network subgraph query`)

if (
networkSubgraphAuthValue &&
req.headers['authorization'] !== networkSubgraphAuthValue
) {
throw new Error(`Invalid auth token`)
}
let networkSubgraphAuthValue: string | undefined
if (networkSubgraphAuthToken) {
networkSubgraphAuthValue = `Bearer ${networkSubgraphAuthToken}`
}

const result = await networkSubgraph.queryRaw(req.body)
res.status(200).contentType('application/json').send(result.data)
} catch (err) {
logger.warn(`Failed to handle network subgraph query`, { err })
return res.status(200).send({ errors: [{ message: err.message }] })
if (
networkSubgraphAuthValue &&
req.headers['authorization'] !== networkSubgraphAuthValue
) {
throw new Error(`Invalid auth token`)
}
},
)

const result = await networkSubgraph.queryRaw(req.body)
res.status(200).contentType('application/json').send(result.data)
} catch (err) {
logger.warn(`Failed to handle network subgraph query`, { err })
return res.status(200).send({ errors: [{ message: err.message }] })
}
})
}

// Endpoint for subgraph queries
app.post(
'/subgraphs/id/:id',

// Accept JSON but don't parse it
bodyParser.raw({ type: 'application/json' }),
rawParser,

async (req, res) => {
const { id } = req.params
Expand Down Expand Up @@ -369,6 +378,9 @@ export const createServer = async ({
networkSubgraph,
networkSubgraphAuthToken,
serveNetworkSubgraph,
infoRateLimit,
statusRateLimit,
bodySizeLimit,
}: ServerOptions): Promise<http.Server> => {
const app = await createApp({
logger,
Expand All @@ -382,6 +394,9 @@ export const createServer = async ({
networkSubgraph,
networkSubgraphAuthToken,
serveNetworkSubgraph,
infoRateLimit,
statusRateLimit,
bodySizeLimit,
})

return app.listen(port, () => {
Expand Down

0 comments on commit fbc026d

Please sign in to comment.