Skip to content

Commit

Permalink
feat(zeebe): normalise useragent, thread config (#94)
Browse files Browse the repository at this point in the history
  • Loading branch information
jwulf authored Mar 26, 2024
1 parent 7537a6b commit c1c4211
Show file tree
Hide file tree
Showing 13 changed files with 149 additions and 45 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/saas.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ jobs:
CAMUNDA_CONSOLE_CLIENT_SECRET: ${{ secrets.CAMUNDA_CONSOLE_CLIENT_SECRET }}
CAMUNDA_CONSOLE_BASE_URL: ${{ secrets.CAMUNDA_CONSOLE_BASE_URL }}
CAMUNDA_CONSOLE_OAUTH_AUDIENCE: ${{ secrets.CAMUNDA_CONSOLE_OAUTH_AUDIENCE}}
CAMUNDA_OAUTH_TOKEN_REFRESH_THRESHOLD_MS: 10000
CAMUNDA_OAUTH_TOKEN_REFRESH_THRESHOLD_MS: 10000 #89: Intermittent 401 unauthorised in integration tests
18 changes: 1 addition & 17 deletions src/__tests__/oauth/OAuthProvider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ test('Gets the token cache dir from the environment', () => {
ZEEBE_CLIENT_SECRET: 'clientSecret',
CAMUNDA_OAUTH_URL: 'url',
},
userAgentString: 'test',
})
expect(o).toBeTruthy()
const exists = fs.existsSync(tokenCacheDir)
Expand All @@ -125,7 +124,6 @@ test('Creates the token cache dir if it does not exist', () => {
ZEEBE_CLIENT_SECRET: 'clientSecret',
CAMUNDA_OAUTH_URL: 'url',
},
userAgentString: 'test',
})

expect(o).toBeTruthy()
Expand All @@ -152,7 +150,6 @@ test('Throws in the constructor if the token cache is not writable', () => {
ZEEBE_CLIENT_SECRET: 'clientSecret',
CAMUNDA_OAUTH_URL: 'url',
},
userAgentString: 'test',
})
expect(o).toBeTruthy()
} catch {
Expand Down Expand Up @@ -181,7 +178,6 @@ test('In-memory cache is populated and evicted after timeout', (done) => {
CAMUNDA_OAUTH_URL: `http://127.0.0.1:${serverPort3002}`,
CAMUNDA_OAUTH_TOKEN_REFRESH_THRESHOLD_MS: 0,
},
userAgentString: 'test',
})

let requestCount = 0
Expand Down Expand Up @@ -235,7 +231,6 @@ test('In-memory cache is populated and evicted respecting CAMUNDA_OAUTH_TOKEN_RE
CAMUNDA_OAUTH_TOKEN_REFRESH_THRESHOLD_MS: 2000,
CAMUNDA_TOKEN_DISK_CACHE_DISABLE: true,
},
userAgentString: 'test',
})

let requestCount = 0
Expand Down Expand Up @@ -283,7 +278,6 @@ test('Uses form encoding for request', (done) => {
ZEEBE_CLIENT_SECRET: 'clientSecret',
CAMUNDA_OAUTH_URL: `http://127.0.0.1:${serverPort3001}`,
},
userAgentString: 'test',
})
server = http
.createServer((req, res) => {
Expand Down Expand Up @@ -318,7 +312,6 @@ test('Uses a custom audience for an Operate token, if one is configured', (done)
CAMUNDA_OAUTH_URL: `http://127.0.0.1:${serverPort3003}`,
CAMUNDA_OPERATE_OAUTH_AUDIENCE: 'custom.operate.audience',
},
userAgentString: 'test',
})
server = http
.createServer((req, res) => {
Expand Down Expand Up @@ -353,7 +346,6 @@ test('Passes scope, if provided', () => {
ZEEBE_CLIENT_SECRET: 'clientSecret',
CAMUNDA_OAUTH_URL: `http://127.0.0.1:${serverPort3004}`,
},
userAgentString: 'test',
})
server = http
.createServer((req, res) => {
Expand Down Expand Up @@ -388,7 +380,6 @@ test('Can get scope from environment', () => {
ZEEBE_CLIENT_SECRET: 'clientSecret',
CAMUNDA_OAUTH_URL: `http://127.0.0.1:${serverPort3005}`,
},
userAgentString: 'test',
})
server = http
.createServer((req, res) => {
Expand Down Expand Up @@ -428,7 +419,6 @@ test('Creates the token cache dir if it does not exist', () => {
ZEEBE_CLIENT_SECRET: 'clientSecret',
CAMUNDA_OAUTH_URL: 'url',
},
userAgentString: 'test',
})

expect(o).toBeTruthy()
Expand All @@ -453,7 +443,6 @@ test('Gets the token cache dir from the environment', () => {
ZEEBE_CLIENT_SECRET: 'clientSecret',
CAMUNDA_OAUTH_URL: 'url',
},
userAgentString: 'test',
})

expect(o).toBeTruthy()
Expand Down Expand Up @@ -482,7 +471,6 @@ test('Uses an explicit token cache over the environment', () => {
ZEEBE_CLIENT_SECRET: 'clientSecret',
CAMUNDA_OAUTH_URL: 'url',
},
userAgentString: 'test',
})

expect(o).toBeTruthy()
Expand Down Expand Up @@ -514,7 +502,6 @@ test('Throws in the constructor if the token cache is not writable', () => {
ZEEBE_CLIENT_SECRET: 'clientSecret',
CAMUNDA_OAUTH_URL: 'url',
},
userAgentString: 'test',
})
expect(o).toBeTruthy()
} catch {
Expand All @@ -534,8 +521,8 @@ test('Can set a custom user agent', () => {
ZEEBE_CLIENT_ID: 'clientId',
ZEEBE_CLIENT_SECRET: 'clientSecret',
CAMUNDA_OAUTH_URL: 'http://127.0.0.1:3005',
CAMUNDA_CUSTOM_USER_AGENT_STRING: 'modeler',
},
userAgentString: 'modeler',
})

expect(o.userAgentString.includes(' modeler')).toBe(true)
Expand All @@ -552,7 +539,6 @@ test('Passes no audience for Modeler API when self-hosted', (done) => {
ZEEBE_CLIENT_SECRET: 'clientSecret',
CAMUNDA_OAUTH_URL: `http://127.0.0.1:${serverPort3006}`,
},
userAgentString: 'modeler',
})
server = http
.createServer((req, res) => {
Expand Down Expand Up @@ -587,7 +573,6 @@ test('Throws if you try to get a Modeler token from SaaS without console creds',
ZEEBE_CLIENT_SECRET: 'clientSecret',
CAMUNDA_OAUTH_URL: 'https://login.cloud.camunda.io/oauth/token',
},
userAgentString: 'modeler',
})

await o
Expand All @@ -611,7 +596,6 @@ test('Throws if you try to get a Modeler token from Self-hosted without applicat
CAMUNDA_CONSOLE_CLIENT_SECRET: 'clientSecret',
CAMUNDA_OAUTH_URL: 'https://localhost',
},
userAgentString: 'modeler',
})
await o
.getToken('MODELER')
Expand Down
4 changes: 2 additions & 2 deletions src/admin/lib/AdminApiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
GetCertificateAuthority,
RequireConfiguration,
constructOAuthProvider,
packageVersion,
createUserAgentString,
} from 'lib'

import { IOAuthProvider } from '../../oauth'
Expand Down Expand Up @@ -38,7 +38,7 @@ export class AdminApiClient {

const certificateAuthority = GetCertificateAuthority(config)

this.userAgentString = `console-client-nodejs/${packageVersion}`
this.userAgentString = createUserAgentString(config)
this.rest = got.extend({
prefixUrl: `${baseUrl}/clusters`,
https: {
Expand Down
92 changes: 92 additions & 0 deletions src/lib/Configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import { createEnv } from 'neon-env'

const getMainEnv = () =>
createEnv({
/** Custom user agent */
CAMUNDA_CUSTOM_USER_AGENT_STRING: {
type: 'string',
optional: true,
},
/** Set to true to disable OAuth completely */
CAMUNDA_OAUTH_DISABLED: {
type: 'boolean',
Expand Down Expand Up @@ -198,9 +203,96 @@ const getZeebeEnv = () =>
optional: true,
default: 3000,
},
/**
* After a duration of this time the client/server pings its peer to see if the transport is still alive.
* Int valued, milliseconds. Defaults to 360000.
*/
GRPC_KEEPALIVE_TIME_MS: {
type: 'number',
optional: true,
default: 360000,
},
/**
* After waiting for a duration of this time, if the keepalive ping sender does not receive the ping ack, it will close the
* transport. Int valued, milliseconds. Defaults to 120000.
*/
GRPC_KEEPALIVE_TIMEOUT_MS: {
type: 'number',
optional: true,
default: 120000,
},
/**
* The time between the first and second connection attempts,
* in ms. Defaults to 1000.
*/
GRPC_INITIAL_RECONNECT_BACKOFF_MS: {
type: 'string',
optional: true,
default: 1000,
},
/**
* The maximum time between subsequent connection attempts,
* in ms. Defaults to 10000.
*/
GRPC_MAX_RECONNECT_BACKOFF_MS: {
type: 'string',
optional: true,
default: 10000,
},
/**
* The minimum time between subsequent connection attempts,
* in ms. Default is 1000ms, but this can cause an SSL Handshake failure.
* This causes an intermittent failure in the Worker-LongPoll test when run
* against Camunda Cloud.
* Raised to 5000ms.
* See: https://github.com/grpc/grpc/issues/8382#issuecomment-259482949
*/
GRPC_MIN_RECONNECT_BACKOFF_MS: {
type: 'string',
optional: true,
default: 5000,
},
/**
* Defaults to 90000.
*/
GRPC_HTTP2_MIN_TIME_BETWEEN_PINGS_MS: {
type: 'number',
optional: true,
default: 90000,
},
/**
* Minimum allowed time between a server receiving
* successive ping frames without sending any data
* frame. Int valued, milliseconds. Default: 90000
*/
GRPC_HTTP2_MIN_PING_INTERVAL_WITHOUT_DATA_MS: {
type: 'number',
optional: true,
default: 90000,
},
/**
* This channel argument if set to 1
* (0 : false; 1 : true), allows keepalive pings
* to be sent even if there are no calls in flight.
* Defaults to 1.
*/
GRPC_KEEPALIVE_PERMIT_WITHOUT_CALLS: {
type: 'number',
optional: true,
default: 1,
},
/**
* This channel argument controls the maximum number
* of pings that can be sent when there is no other
* data (data frame or header frame) to be sent.
* GRPC Core will not continue sending pings if we
* run over the limit. Setting it to 0 allows sending
* pings without sending data.
*/
GRPC_HTTP2_MAX_PINGS_WITHOUT_DATA: {
type: 'number',
optional: true,
default: 0,
},
/** Zeebe client log output can be human-readable 'SIMPLE' or structured 'JSON'. Defaults to 'SIMPLE' */
ZEEBE_CLIENT_LOG_TYPE: {
Expand Down
10 changes: 10 additions & 0 deletions src/lib/CreateUserAgentString.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { CamundaPlatform8Configuration, DeepPartial } from './Configuration'
import { packageVersion } from './GetPackageVersion'

export const createUserAgentString = (
config: DeepPartial<CamundaPlatform8Configuration>
) => {
const userAgent = `camunda8-sdk-nodejs/${packageVersion}`
const customUserAgent = config.CAMUNDA_CUSTOM_USER_AGENT_STRING
return customUserAgent ? `${userAgent} ${customUserAgent}` : `${userAgent}`
}
1 change: 1 addition & 0 deletions src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from './CertificateAuthority'
export * from './ClientConstructor'
export * from './Configuration'
export * from './ConstructOAuthProvider'
export * from './CreateUserAgentString'
export * from './Delay'
export * from './EnvironmentSetup'
export { packageVersion } from './GetPackageVersion'
Expand Down
4 changes: 2 additions & 2 deletions src/modeler/lib/ModelerAPIClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
DeepPartial,
GetCertificateAuthority,
constructOAuthProvider,
packageVersion,
createUserAgentString,
} from 'lib'
import { IOAuthProvider } from 'oauth'

Expand All @@ -32,7 +32,7 @@ export class ModelerApiClient {
config.CAMUNDA_MODELER_BASE_URL ?? 'https://modeler.cloud.camunda.io/api'
this.oAuthProvider =
options?.oAuthProvider ?? constructOAuthProvider(config)
this.userAgentString = `modeler-client-nodejs/${packageVersion}`
this.userAgentString = createUserAgentString(config)
const prefixUrl = `${modelerApiUrl}/${API_VERSION}`

const certificateAuthority = GetCertificateAuthority(config)
Expand Down
7 changes: 2 additions & 5 deletions src/oauth/lib/OAuthProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
DeepPartial,
GetCertificateAuthority,
RequireConfiguration,
packageVersion,
createUserAgentString,
} from 'lib'
import fetch from 'node-fetch'

Expand Down Expand Up @@ -45,7 +45,6 @@ export class OAuthProvider implements IOAuthProvider {

constructor(options?: {
config?: DeepPartial<CamundaPlatform8Configuration>
userAgentString?: string
}) {
const config = CamundaEnvironmentConfigurator.mergeConfigWithEnvironment(
options?.config ?? {}
Expand Down Expand Up @@ -92,9 +91,7 @@ export class OAuthProvider implements IOAuthProvider {
this.cacheDir =
config.CAMUNDA_TOKEN_CACHE_DIR ?? OAuthProvider.defaultTokenCache

this.userAgentString = `camunda-8-sdk-nodejs/${packageVersion}${
options?.userAgentString ? ' ' + options?.userAgentString : ''
}` // e.g.: `zeebe-client-nodejs/${pkg.version} ${CUSTOM_AGENT_STRING}`
this.userAgentString = createUserAgentString(config)

/**
* CAMUNDA_MODELER_OAUTH_AUDIENCE is optional, and only needed if the Modeler is running on Self-Managed
Expand Down
4 changes: 2 additions & 2 deletions src/operate/lib/OperateApiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
GetCertificateAuthority,
RequireConfiguration,
constructOAuthProvider,
packageVersion,
createUserAgentString,
parseArrayWithAnnotations,
parseWithAnnotations,
} from 'lib'
Expand Down Expand Up @@ -79,7 +79,7 @@ export class OperateApiClient {
)
this.oAuthProvider =
options?.oAuthProvider ?? constructOAuthProvider(config)
this.userAgentString = `operate-client-nodejs/${packageVersion}`
this.userAgentString = createUserAgentString(config)
const baseUrl = RequireConfiguration(
config.CAMUNDA_OPERATE_BASE_URL,
'CAMUNDA_OPERATE_BASE_URL'
Expand Down
4 changes: 2 additions & 2 deletions src/optimize/lib/OptimizeApiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
GetCertificateAuthority,
RequireConfiguration,
constructOAuthProvider,
packageVersion,
createUserAgentString,
} from 'lib'
import { IOAuthProvider } from 'oauth'

Expand Down Expand Up @@ -60,7 +60,7 @@ export class OptimizeApiClient {
const config = CamundaEnvironmentConfigurator.mergeConfigWithEnvironment(
options?.config ?? {}
)
this.userAgentString = `optimize-client-nodejs/${packageVersion}`
this.userAgentString = createUserAgentString(config)
const baseUrl = RequireConfiguration(
config.CAMUNDA_OPTIMIZE_BASE_URL,
'CAMUNDA_OPTIMIZE_BASE_URL'
Expand Down
4 changes: 2 additions & 2 deletions src/tasklist/lib/TasklistApiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
GetCertificateAuthority,
RequireConfiguration,
constructOAuthProvider,
packageVersion,
createUserAgentString,
parseArrayWithAnnotations,
parseWithAnnotations,
} from 'lib'
Expand Down Expand Up @@ -63,7 +63,7 @@ export class TasklistApiClient {
)
this.oAuthProvider =
options?.oAuthProvider ?? constructOAuthProvider(config)
this.userAgentString = `tasklist-rest-client-nodejs/${packageVersion}`
this.userAgentString = createUserAgentString(config)
const baseUrl = RequireConfiguration(
config.CAMUNDA_TASKLIST_BASE_URL,
'CAMUNDA_TASKLIST_BASE_URL'
Expand Down
Loading

0 comments on commit c1c4211

Please sign in to comment.