Skip to content
This repository has been archived by the owner on Apr 8, 2024. It is now read-only.

Commit

Permalink
Merge pull request #331 from camunda-community-hub/multi-tenant-start
Browse files Browse the repository at this point in the history
add support for tenantId
  • Loading branch information
jwulf committed Oct 20, 2023
2 parents 01d22ff + 9ab31ad commit 64d0e9f
Show file tree
Hide file tree
Showing 30 changed files with 492 additions and 153 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
services:
zeebe:
image: camunda/zeebe:8.2.3
image: camunda/zeebe:8.3.0
ports:
- 26500:26500
steps:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ tsconfig.tsbuildinfo
ignore-this
.dccache
target/npmlist.json
*.env
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
# 8.3.0

## Breaking changes

_Changes in APIs or behaviour that may affect existing applications that use zeebe-node._

- Several method signatures for `CreateProcessInstance` and `CreateProcessInstanceWithResult` have been removed, leaving only the method that takes an object parameter. See [#330](https://github.com/camunda-community-hub/zeebe-client-node-js/issues/330#issuecomment-1672535320) for more details.

## New Features

_New shiny stuff._

- Camunda Platform 8.3.0 introduces multi-tenancy. To support this, the Node.js client adds an optional `tenantId` parameter to `DeployResource`, `DeployProcess`, `CreateProcessInstance`, `CreateProcessInstanceWithResult`, and `PublishMessage`. You can also specify a `tenantId` in the ZBClient constructor or via the environment variable `ZEEBE_TENANT_ID`. This will be transparently added to all method invocations. See [#330](https://github.com/camunda-community-hub/zeebe-client-node-js/issues/330) for more details.

# Version 8.2.5

## New Features
Expand Down
53 changes: 42 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,10 @@ async function main() {

// Create a process instance of the 'new-customer-process' process, with a customerId variable set
// 'createProcessInstanceWithResult' awaits the outcome
const outcome = await zbc.createProcessInstanceWithResult('new-customer-process', { customerId: 457 });
const outcome = await zbc.createProcessInstanceWithResult({
bpmnProcessId: 'new-customer-process',
variables: { customerId: 457 }
});
// Log the process outcome
console.log('Process outcome', JSON.stringify(outcome, null, 2));
}
Expand Down Expand Up @@ -402,11 +405,11 @@ zbWorker.on('connectionError', () => console.log(`Worker disconnected!`))

### Initial Connection Tolerance

Some broker connections can initially emit error messages - for example: when connecting to Camunda Cloud, during TLS negotiation and OAuth authentication, the eager commands used to detect connection status will fail, and the library will report connection errors.
Some broker connections can initially emit error messages - for example: when connecting to Camunda SaaS, during TLS negotiation and OAuth authentication, the eager commands used to detect connection status will fail, and the library will report connection errors.

Since this is expected behaviour - a _characteristic of that particular connection_ - the library has a configurable "_initial connection tolerance_". This is a number of milliseconds representing the expected window in which these errors will occur on initial connection.

If the library detects that you are connecting to Camunda Cloud, it sets this window to five seconds (5000 milliseconds). In some environments and under some conditions this may not be sufficient (like connecting to Camunda Cloud from your apartment Wi-fi in South Brisbane, Australia on a rainy day while the microwave link to the next suburb's ADSL exchange is degraded).
If the library detects that you are connecting to Camunda SaaS, it sets this window to five seconds (5000 milliseconds). In some environments and under some conditions this may not be sufficient.

You can set an explicit value for this using the environment variable `ZEEBE_INITIAL_CONNECTION_TOLERANCE`, set to a number of milliseconds.

Expand Down Expand Up @@ -518,11 +521,11 @@ Basic Auth will also work without TLS.
<a name = "camunda-cloud"></a>
### Camunda Cloud
### Camunda 8 SaaS
[Camunda Cloud](https://camunda.io) is a hosted SaaS instance of Zeebe. The easiest way to connect is to use the [Zero-conf constructor](#zero-conf) with the Client Credentials from the Camunda Cloud console as environment variables.
[Camunda 8 SaaS](https://camunda.io) is a hosted SaaS instance of Zeebe. The easiest way to connect is to use the [Zero-conf constructor](#zero-conf) with the Client Credentials from the Camunda SaaS console as environment variables.
You can also connect to Camunda Cloud by using the `camundaCloud` configuration option, using the `clusterId`, `clientSecret`, and `clientId` from the Camunda Cloud Console, like this:
You can also connect to Camunda SaaS by using the `camundaCloud` configuration option, using the `clusterId`, `clientSecret`, and `clientId` from the Camunda SaaS Console, like this:
```typescript
const { ZBClient } = require('zeebe-node')
Expand All @@ -537,7 +540,7 @@ const zbc = new ZBClient({
})
```
That's it! Under the hood, the client lib will construct the OAuth configuration for Camunda Cloud and set the gateway address and port for you.
That's it! Under the hood, the client lib will construct the OAuth configuration for Camunda SaaS and set the gateway address and port for you.
We recommend the [Zero-conf constructor](#zero-conf) with the configuration passed in via environment variables. This allows you to run your application against different environments via configuration.
Expand All @@ -559,12 +562,20 @@ With no relevant environment variables set, it will default to localhost on the
The following environment variable configurations are possible with the Zero-conf constructor:
From 8.3.0, multi-tenancy:
```bash
ZEEBE_TENANT_ID
```
Camunda SaaS:
```bash
ZEEBE_ADDRESS
ZEEBE_CLIENT_SECRET
ZEEBE_CLIENT_ID
ZEEBE_TOKEN_AUDIENCE
ZEEBE_AUTHORIZATION_SERVER_URL
```
Self-hosted or local broker (no TLS or OAuth):
Expand Down Expand Up @@ -592,6 +603,20 @@ ZEEBE_AUTHORIZATION_SERVER_URL
ZEEBE_ADDRESS
```
Multi-tenant self-hosted or local broker with OAuth and no TLS:
```bash
ZEEBE_TENANT_ID='<default>'
ZEEBE_SECURE_CONNECTION=false
ZEEBE_ADDRESS='localhost:26500'
ZEEBE_CLIENT_ID='zeebe'
ZEEBE_CLIENT_SECRET='zecret'
ZEEBE_AUTHORIZATION_SERVER_URL='http://localhost:18080/auth/realms/camunda-platform/protocol/openid-connect/token'
ZEEBE_TOKEN_AUDIENCE='zeebe.camunda.io'
CAMUNDA_CREDENTIALS_SCOPES='Zeebe'
CAMUNDA_OAUTH_URL='http://localhost:18080/auth/realms/camunda-platform/protocol/openid-connect/token'
```
Basic Auth:
```bash
Expand Down Expand Up @@ -1150,8 +1175,11 @@ const ZB = require('zeebe-node')

;(async () => {
const zbc = new ZB.ZBClient('localhost:26500')
const result = await zbc.createProcessInstance('test-process', {
testData: 'something',
const result = await zbc.createProcessInstance({
bpmnProcessId: 'test-process',
variables: {
testData: 'something'
}
})
console.log(result)
})()
Expand Down Expand Up @@ -1198,8 +1226,11 @@ From version 0.22 of the broker and client, you can await the outcome of a proce
```typescript
async function getOutcome() {
const result = await zbc.createProcessInstanceWithResult(processId, {
sourceValue: 5,
const result = await zbc.createProcessInstanceWithResult({
bpmnProcessId: processId,
variables: {
sourceValue: 5
}
})
return result
}
Expand Down
2 changes: 1 addition & 1 deletion docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ services:
zeebe:
restart: always
container_name: zeebe_broker
image: camunda/zeebe:8.1.6
image: camunda/zeebe:8.3.0
environment:
- ZEEBE_LOG_LEVEL=debug
volumes:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "zeebe-node",
"version": "8.2.5",
"version": "8.3.0-alpha7",
"description": "The Node.js client library for the Zeebe Workflow Automation Engine.",
"keywords": [
"zeebe",
Expand Down
80 changes: 80 additions & 0 deletions proto/zeebe.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,22 @@ option go_package = "./;pb";
// For a more complete documentation, refer to Zeebe documentation at:
// https://docs.camunda.io/docs/reference/grpc

message StreamActivatedJobsRequest {
// the job type, as defined in the BPMN process (e.g. <zeebe:taskDefinition
// type="payment-service" />)
string type = 1;
// the name of the worker activating the jobs, mostly used for logging purposes
string worker = 2;
// a job returned after this call will not be activated by another call until the
// timeout (in ms) has been reached
int64 timeout = 3;
// a list of variables to fetch as the job variables; if empty, all visible variables at
// the time of activation for the scope of the job will be returned
repeated string fetchVariable = 5;
// a list of identifiers of tenants for which to stream jobs
repeated string tenantIds = 6;
}

message ActivateJobsRequest {
// the job type, as defined in the BPMN process (e.g. <zeebe:taskDefinition
// type="payment-service" />)
Expand All @@ -26,6 +42,8 @@ message ActivateJobsRequest {
// if the requestTimeout = 0, a default timeout is used.
// if the requestTimeout < 0, long polling is disabled and the request is completed immediately, even when no job is activated.
int64 requestTimeout = 6;
// a list of IDs of tenants for which to activate jobs
repeated string tenantIds = 7;
}

message ActivateJobsResponse {
Expand Down Expand Up @@ -63,6 +81,8 @@ message ActivatedJob {
// JSON document, computed at activation time, consisting of all visible variables to
// the task scope
string variables = 13;
// // the id of the tenant that owns the job
string tenantId = 14;
}

message CancelProcessInstanceRequest {
Expand Down Expand Up @@ -102,6 +122,8 @@ message CreateProcessInstanceRequest {
// will start at the start event. If non-empty the process instance will apply start
// instructions after it has been created
repeated ProcessInstanceCreationStartInstruction startInstructions = 5;
// the tenant id of the process definition
string tenantId = 6;
}

message ProcessInstanceCreationStartInstruction {
Expand All @@ -128,6 +150,8 @@ message CreateProcessInstanceResponse {
// the unique identifier of the created process instance; to be used wherever a request
// needs a process instance key (e.g. CancelProcessInstanceRequest)
int64 processInstanceKey = 4;
// the tenant identifier of the created process instance
string tenantId = 5;
}

message CreateProcessInstanceWithResultRequest {
Expand Down Expand Up @@ -155,6 +179,8 @@ message CreateProcessInstanceWithResultResponse {
// JSON document
// consists of visible variables in the root scope
string variables = 5;
// the tenant identifier of the process definition
string tenantId = 6;
}

message EvaluateDecisionRequest {
Expand All @@ -170,6 +196,8 @@ message EvaluateDecisionRequest {
// [{ "a": 1, "b": 2 }] would not be a valid argument, as the root of the
// JSON document is an array and not an object.
string variables = 3;
// the tenant identifier of the decision
string tenantId = 4;
}

message EvaluateDecisionResponse {
Expand Down Expand Up @@ -199,6 +227,8 @@ message EvaluateDecisionResponse {
string failedDecisionId = 9;
// an optional message describing why the decision which was evaluated failed
string failureMessage = 10;
// the tenant identifier of the evaluated decision
string tenantId = 11;
}

message EvaluatedDecision {
Expand All @@ -221,6 +251,8 @@ message EvaluatedDecision {
repeated MatchedDecisionRule matchedRules = 7;
// the decision inputs that were evaluated within this decision evaluation
repeated EvaluatedDecisionInput evaluatedInputs = 8;
// the tenant identifier of the evaluated decision
string tenantId = 9;
}

message EvaluatedDecisionInput {
Expand Down Expand Up @@ -278,6 +310,8 @@ message DeployProcessResponse {
message DeployResourceRequest {
// list of resources to deploy
repeated Resource resources = 1;
// the tenant id of the resources to deploy
string tenantId = 2;
}

message Resource {
Expand All @@ -292,6 +326,8 @@ message DeployResourceResponse {
int64 key = 1;
// a list of deployed resources, e.g. processes
repeated Deployment deployments = 2;
// the tenant id of the deployed resources
string tenantId = 3;
}

message Deployment {
Expand All @@ -303,6 +339,8 @@ message Deployment {
DecisionMetadata decision = 2;
// metadata of a deployed decision requirements
DecisionRequirementsMetadata decisionRequirements = 3;
// metadata of a deployed form
FormMetadata form = 4;
}
}

Expand All @@ -317,6 +355,8 @@ message ProcessMetadata {
// the resource name (see: ProcessRequestObject.name) from which this process was
// parsed
string resourceName = 4;
// the tenant id of the deployed process
string tenantId = 5;
}

message DecisionMetadata {
Expand All @@ -336,6 +376,8 @@ message DecisionMetadata {
// the assigned key of the decision requirements graph that this decision is
// part of
int64 decisionRequirementsKey = 6;
// the tenant id of the deployed decision
string tenantId = 7;
}

message DecisionRequirementsMetadata {
Expand All @@ -352,6 +394,22 @@ message DecisionRequirementsMetadata {
// the resource name (see: Resource.name) from which this decision
// requirements was parsed
string resourceName = 5;
// the tenant id of the deployed decision requirements
string tenantId = 6;
}

message FormMetadata {
// the form ID, as parsed during deployment; together with the
// versions forms a unique identifier for a specific form
string formId = 1;
// the assigned form version
int32 version = 2;
// the assigned key, which acts as a unique identifier for this form
int64 formKey = 3;
// the resource name
string resourceName = 4;
// the tenant id of the deployed form
string tenantId = 5;
}

message FailJobRequest {
Expand Down Expand Up @@ -407,11 +465,15 @@ message PublishMessageRequest {
// the message variables as a JSON document; to be valid, the root of the document must be an
// object, e.g. { "a": "foo" }. [ "foo" ] would not be valid.
string variables = 5;
// the tenant id of the message
string tenantId = 6;
}

message PublishMessageResponse {
// the unique ID of the message that was published
int64 key = 1;
// the tenant id of the message
string tenantId = 2;
}

message ResolveIncidentRequest {
Expand Down Expand Up @@ -588,6 +650,18 @@ service Gateway {
rpc ActivateJobs (ActivateJobsRequest) returns (stream ActivateJobsResponse) {
}

/*
Registers client to a job stream that will stream jobs back to the client as
they become activatable.
Errors:
INVALID_ARGUMENT:
- type is blank (empty string, null)
- timeout less than 1
*/
rpc StreamActivatedJobs (StreamActivatedJobsRequest) returns (stream ActivatedJob) {
}

/*
Cancels a running process instance
Expand Down Expand Up @@ -679,11 +753,17 @@ service Gateway {
Note that this is an atomic call, i.e. either all resources are deployed, or none of them are.
Errors:
PERMISSION_DENIED:
- if a deployment to an unauthorized tenant is performed
INVALID_ARGUMENT:
- no resources given.
- if at least one resource is invalid. A resource is considered invalid if:
- the content is not deserializable (e.g. detected as BPMN, but it's broken XML)
- the content is invalid (e.g. an event-based gateway has an outgoing sequence flow to a task)
- if multi-tenancy is enabled, and:
- a tenant id is not provided
- a tenant id with an invalid format is provided
- if multi-tenancy is disabled and a tenant id is provided
*/
rpc DeployResource (DeployResourceRequest) returns (DeployResourceResponse) {
}
Expand Down
File renamed without changes.
Loading

0 comments on commit 64d0e9f

Please sign in to comment.