Skip to content
12 changes: 1 addition & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/dev-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
},
"author": "Netlify Inc.",
"devDependencies": {
"@netlify/types": "2.0.1",
"@netlify/types": "2.0.2",
"@types/lodash.debounce": "^4.0.9",
"@types/node": "^18.19.110",
"@types/parse-gitignore": "^1.0.2",
Expand Down
1 change: 1 addition & 0 deletions packages/functions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
"@netlify/blobs": "10.0.6",
"@netlify/dev-utils": "4.0.0",
"@netlify/serverless-functions-api": "2.1.3",
"@netlify/types": "2.0.2",
"@netlify/zip-it-and-ship-it": "^14.1.0",
"cron-parser": "^4.9.0",
"decache": "^4.6.2",
Expand Down
79 changes: 79 additions & 0 deletions packages/functions/src/lib/consts.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { describe, expect, test } from 'vitest'

import { BACKGROUND_FUNCTION_TIMEOUT, getFunctionTimeout, SYNCHRONOUS_FUNCTION_TIMEOUT } from './consts.js'

describe('Function timeout constants', () => {
test('exports correct timeout values', () => {
expect(SYNCHRONOUS_FUNCTION_TIMEOUT).toBe(30)
expect(BACKGROUND_FUNCTION_TIMEOUT).toBe(900)
})
})

describe('getFunctionTimeout', () => {
test('returns default timeout for synchronous functions when no site config', () => {
const result = getFunctionTimeout({})
expect(result).toBe(SYNCHRONOUS_FUNCTION_TIMEOUT)
})

test('returns default timeout for background functions when no site config', () => {
const result = getFunctionTimeout({}, true)
expect(result).toBe(BACKGROUND_FUNCTION_TIMEOUT)
})

test('respects functionsTimeout from site config for synchronous functions', () => {
const siteConfig = { functionsTimeout: 60 }
const result = getFunctionTimeout(siteConfig)
expect(result).toBe(60)
})

test('respects functionsTimeout from site config for background functions', () => {
const siteConfig = { functionsTimeout: 1800 }
const result = getFunctionTimeout(siteConfig, true)
expect(result).toBe(1800)
})

test('respects functionsConfig.timeout from site config for synchronous functions', () => {
const siteConfig = { functionsConfig: { timeout: 45 } }
const result = getFunctionTimeout(siteConfig)
expect(result).toBe(45)
})

test('respects functionsConfig.timeout from site config for background functions', () => {
const siteConfig = { functionsConfig: { timeout: 1200 } }
const result = getFunctionTimeout(siteConfig, true)
expect(result).toBe(1200)
})

test('prioritizes functionsTimeout over functionsConfig.timeout', () => {
const siteConfig = {
functionsTimeout: 60,
functionsConfig: { timeout: 45 },
}
const result = getFunctionTimeout(siteConfig)
expect(result).toBe(60)
})

test('handles undefined functionsConfig', () => {
const siteConfig = { functionsConfig: undefined }
const result = getFunctionTimeout(siteConfig)
expect(result).toBe(SYNCHRONOUS_FUNCTION_TIMEOUT)
})

test('handles empty functionsConfig object', () => {
const siteConfig = { functionsConfig: {} }
const result = getFunctionTimeout(siteConfig)
expect(result).toBe(SYNCHRONOUS_FUNCTION_TIMEOUT)
})

test('handles undefined timeout in functionsConfig', () => {
const siteConfig = { functionsConfig: { timeout: undefined } }
const result = getFunctionTimeout(siteConfig)
expect(result).toBe(SYNCHRONOUS_FUNCTION_TIMEOUT)
})

test('handles zero timeout values', () => {
const siteConfig = { functionsTimeout: 0 }
const result = getFunctionTimeout(siteConfig)
expect(result).toBe(0)
})
})
39 changes: 38 additions & 1 deletion packages/functions/src/lib/consts.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,43 @@
import type { SiteConfig } from '@netlify/types'

const BUILDER_FUNCTIONS_FLAG = true
const HTTP_STATUS_METHOD_NOT_ALLOWED = 405
const HTTP_STATUS_OK = 200
const METADATA_VERSION = 1

export { BUILDER_FUNCTIONS_FLAG, HTTP_STATUS_METHOD_NOT_ALLOWED, HTTP_STATUS_OK, METADATA_VERSION }
/**
* Default timeout for synchronous functions in seconds
*/
const SYNCHRONOUS_FUNCTION_TIMEOUT = 30

/**
* Default timeout for background functions in seconds
*/
const BACKGROUND_FUNCTION_TIMEOUT = 900

/**
* Get the effective function timeout considering site-specific configuration
* @param siteConfig - Site configuration with timeout options
* @param isBackground - Whether this is a background function
* @returns Function timeout in seconds
*/
export function getFunctionTimeout(siteConfig: SiteConfig, isBackground = false): number {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a file called consts.ts so I'm not convinced it should export functions. let's move this to where it's used instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved the getFunctionTimeout function from consts.ts to where it's actually used in the registry and main dev files. Functions stay in consts.ts, behavior moves to where it's needed. Commit: b4f8e3e

// Check for site-specific timeout configuration
const siteTimeout = siteConfig.functionsTimeout ?? siteConfig.functionsConfig?.timeout

if (siteTimeout !== undefined) {
return siteTimeout
}

// Use default timeout based on function type
return isBackground ? BACKGROUND_FUNCTION_TIMEOUT : SYNCHRONOUS_FUNCTION_TIMEOUT
}

export {
BUILDER_FUNCTIONS_FLAG,
HTTP_STATUS_METHOD_NOT_ALLOWED,
HTTP_STATUS_OK,
METADATA_VERSION,
SYNCHRONOUS_FUNCTION_TIMEOUT,
BACKGROUND_FUNCTION_TIMEOUT,
}
1 change: 1 addition & 0 deletions packages/functions/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export { purgeCache } from './lib/purge_cache.js'
export { schedule } from './lib/schedule.js'
export { stream } from './lib/stream.js'
export * from './function/index.js'
export { SYNCHRONOUS_FUNCTION_TIMEOUT, BACKGROUND_FUNCTION_TIMEOUT, getFunctionTimeout } from './lib/consts.js'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's no need to export these

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the unnecessary exports from main.ts. The timeout logic is now properly contained within the functions where it's used. Commit: b4f8e3e

68 changes: 68 additions & 0 deletions packages/types/src/lib/context/site.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { describe, expect, expectTypeOf, test } from 'vitest'

import type { Site, SiteConfig } from './site.js'

describe('Site types', () => {
test('Site interface accepts all optional properties', () => {
const site: Site = {}
expect(site).toBeDefined()

const siteWithProps: Site = {
id: 'site-id',
name: 'My Site',
url: 'https://example.com',
}
expect(siteWithProps.id).toBe('site-id')
expect(siteWithProps.name).toBe('My Site')
expect(siteWithProps.url).toBe('https://example.com')
})

test('SiteConfig interface accepts optional timeout properties', () => {
const config: SiteConfig = {}
expect(config).toBeDefined()

const configWithFunctionsTimeout: SiteConfig = {
functionsTimeout: 60,
}
expect(configWithFunctionsTimeout.functionsTimeout).toBe(60)

const configWithFunctionsConfig: SiteConfig = {
functionsConfig: {
timeout: 45,
},
}
expect(configWithFunctionsConfig.functionsConfig?.timeout).toBe(45)

const configWithBoth: SiteConfig = {
functionsTimeout: 60,
functionsConfig: {
timeout: 45,
},
}
expect(configWithBoth.functionsTimeout).toBe(60)
expect(configWithBoth.functionsConfig?.timeout).toBe(45)
})

test('timeout values have correct types', () => {
const config: SiteConfig = {
functionsTimeout: 30,
functionsConfig: {
timeout: 900,
},
}

expect(config.functionsTimeout).toBe(30)
expect(config.functionsConfig?.timeout).toBe(900)

expectTypeOf(config.functionsTimeout).toEqualTypeOf<number | undefined>()
expectTypeOf(config.functionsConfig).toEqualTypeOf<{ timeout?: number } | undefined>()

if (config.functionsTimeout) {
expectTypeOf(config.functionsTimeout).toBeNumber()
}

if (config.functionsConfig?.timeout) {
expectTypeOf(config.functionsConfig.timeout).toBeNumber()
}
})
})
16 changes: 16 additions & 0 deletions packages/types/src/lib/context/site.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,19 @@ export interface Site {
name?: string
url?: string
}

/**
* Site configuration for function timeout options
*/
export interface SiteConfig {
/**
* Site-specific function timeout in seconds
*/
functionsTimeout?: number
/**
* Function-specific timeout configuration
*/
functionsConfig?: {
timeout?: number
}
}
1 change: 1 addition & 0 deletions packages/types/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export type { Context } from './lib/context/context.js'
export type { Cookie } from './lib/context/cookies.js'
export type { EnvironmentVariables } from './lib/environment-variables.js'
export type { NetlifyGlobal } from './lib/globals.js'
export type { Site, SiteConfig } from './lib/context/site.js'
Loading