From 3d8ded492b76be454ddd2907336cacf24cc14ff0 Mon Sep 17 00:00:00 2001 From: ls147258 Date: Fri, 16 Oct 2026 19:35:50 +0800 Subject: [PATCH] fix(deploy): disable idleTimeout when removed or set to 0 in yaml UpdateFunction keeps the online value when the field is omitted, and the server rejects 0 (min 300), so removing idleTimeout from s.yaml never took effect. -1 is the only accepted value that disables it, matching the state the console writes when the toggle is off. - add idleTimeout: -1 to FC_RESOURCES_EMPTY_CONFIG so an unset prop clears the online value like other empty configs - normalize idleTimeout 0/null in props to -1 during deploy - add unit tests for unset/0/null/configured idleTimeout - bump component version to 0.1.27 --- .../ut/commands/deploy/impl/function_test.ts | 92 +++++++++++++++++++ publish.yaml | 2 +- src/default/config.ts | 2 + src/subCommands/deploy/impl/function.ts | 5 + 4 files changed, 100 insertions(+), 1 deletion(-) diff --git a/__tests__/ut/commands/deploy/impl/function_test.ts b/__tests__/ut/commands/deploy/impl/function_test.ts index d3830585..cb14a8de 100644 --- a/__tests__/ut/commands/deploy/impl/function_test.ts +++ b/__tests__/ut/commands/deploy/impl/function_test.ts @@ -378,6 +378,98 @@ describe('Service', () => { }, ); }); + + it('should set idleTimeout to -1 when it is not configured', async () => { + service = new Service(mockInputs, mockOpts); + service.needDeploy = true; + Object.defineProperty(service, 'type', { + value: 'config', + writable: true, + }); + + const mockFcSdk = { + deployFunction: jest.fn().mockResolvedValue(undefined), + }; + Object.defineProperty(service, 'fcSdk', { + value: mockFcSdk, + writable: true, + }); + + jest.spyOn(service as any, '_deployAuto').mockResolvedValue(undefined); + + await service.run(); + + expect(service.fcSdk.deployFunction).toHaveBeenCalledWith( + expect.objectContaining({ + idleTimeout: -1, + }), + expect.anything(), + ); + }); + + it('should convert idleTimeout 0 or null to -1', async () => { + for (const idleTimeout of [0, null]) { + service = new Service( + { ...mockInputs, props: { ...mockInputs.props, idleTimeout } } as any, + mockOpts, + ); + service.needDeploy = true; + Object.defineProperty(service, 'type', { + value: 'config', + writable: true, + }); + + const mockFcSdk = { + deployFunction: jest.fn().mockResolvedValue(undefined), + }; + Object.defineProperty(service, 'fcSdk', { + value: mockFcSdk, + writable: true, + }); + + jest.spyOn(service as any, '_deployAuto').mockResolvedValue(undefined); + + await service.run(); + + expect(service.fcSdk.deployFunction).toHaveBeenCalledWith( + expect.objectContaining({ + idleTimeout: -1, + }), + expect.anything(), + ); + } + }); + + it('should keep configured idleTimeout', async () => { + service = new Service( + { ...mockInputs, props: { ...mockInputs.props, idleTimeout: 600 } } as any, + mockOpts, + ); + service.needDeploy = true; + Object.defineProperty(service, 'type', { + value: 'config', + writable: true, + }); + + const mockFcSdk = { + deployFunction: jest.fn().mockResolvedValue(undefined), + }; + Object.defineProperty(service, 'fcSdk', { + value: mockFcSdk, + writable: true, + }); + + jest.spyOn(service as any, '_deployAuto').mockResolvedValue(undefined); + + await service.run(); + + expect(service.fcSdk.deployFunction).toHaveBeenCalledWith( + expect.objectContaining({ + idleTimeout: 600, + }), + expect.anything(), + ); + }); }); describe('_getAcr', () => { diff --git a/publish.yaml b/publish.yaml index 643e2a98..65cb28f1 100644 --- a/publish.yaml +++ b/publish.yaml @@ -3,7 +3,7 @@ Type: Component Name: fc3 Provider: - 阿里云 -Version: 0.1.25 +Version: 0.1.27 Description: 阿里云函数计算全生命周期管理 HomePage: https://github.com/devsapp/fc3 Organization: 阿里云函数计算(FC) diff --git a/src/default/config.ts b/src/default/config.ts index f8ef3d9d..1936d102 100644 --- a/src/default/config.ts +++ b/src/default/config.ts @@ -42,6 +42,8 @@ export const FC_RESOURCES_EMPTY_CONFIG = { layers: [], instanceIsolationMode: 'SHARE', sessionAffinity: 'NONE', + // 服务端不支持通过省略该字段或置 0 清除线上值,-1 表示关闭延时释放弹性实例 + idleTimeout: -1, }; export const FC_TRIGGER_DEFAULT_CONFIG = { diff --git a/src/subCommands/deploy/impl/function.ts b/src/subCommands/deploy/impl/function.ts index 51821cb4..ddb40e60 100644 --- a/src/subCommands/deploy/impl/function.ts +++ b/src/subCommands/deploy/impl/function.ts @@ -124,6 +124,11 @@ export default class Service extends Base { } // 部署函数 const config = _.defaults(this.local, FC_RESOURCES_EMPTY_CONFIG); + // idleTimeout 0 / null 均非法(服务端最小 300 且不支持空值清除),与未配置一致按关闭处理 + if (config.idleTimeout === 0 || config.idleTimeout === null) { + logger.debug('idleTimeout 0/null is converted to -1 (disabled)'); + config.idleTimeout = -1; + } if ( !_.isEmpty(config.sessionAffinityConfig) && typeof config.sessionAffinityConfig !== 'string'