All Projects → VilledeMontreal → workit

VilledeMontreal / workit

Licence: MIT License
Extensible worker for Node.js that works with both Zeebe and Camunda BPM platforms powered by TypeScript

Programming Languages

typescript
32286 projects
javascript
184084 projects - #8 most used programming language
shell
77523 projects

Projects that are alternatives of or similar to workit

node-red-contrib-zeebe
Zeebe nodes for Node-RED
Stars: ✭ 23 (-54.9%)
Mutual labels:  camunda, zeebe
camunda-cloud-helm
Camunda Platform 8 Self-Managed Helm charts
Stars: ✭ 41 (-19.61%)
Mutual labels:  camunda, zeebe
spring-zeebe
Easily use the Zeebe Java Client in your Spring or Spring Boot projects
Stars: ✭ 103 (+101.96%)
Mutual labels:  zeebe
Worker
The Hoa\Worker library.
Stars: ✭ 25 (-50.98%)
Mutual labels:  worker
event-worker
A simpler way of dealing with Web Workers
Stars: ✭ 18 (-64.71%)
Mutual labels:  worker
nestjs-zeebe
Zeebe transport and client for nestjs framework
Stars: ✭ 40 (-21.57%)
Mutual labels:  zeebe
awesome-camunda-cloud
Awesome Camunda Cloud Projects
Stars: ✭ 81 (+58.82%)
Mutual labels:  zeebe
open-telemetry-java-guides
Java OpenTelemetry 测试指南 :Open-Telemetry-Java-Guides 案例,用于测试常用中间件支持及 Otel 相关组件的使用情况。 可观察性Sig: https://i.cloudnative.to/observability/
Stars: ✭ 67 (+31.37%)
Mutual labels:  opentelemetry
eze
Embedded Zeebe Engine
Stars: ✭ 13 (-74.51%)
Mutual labels:  zeebe
opentelemetry-application-insights
OpenTelemetry exporter for Azure Application Insights
Stars: ✭ 17 (-66.67%)
Mutual labels:  opentelemetry
zeeqs
Query API for aggregated Zeebe data
Stars: ✭ 37 (-27.45%)
Mutual labels:  zeebe
zeebe-client-node-js
Node.js client library for Zeebe Microservices Orchestration Engine
Stars: ✭ 109 (+113.73%)
Mutual labels:  zeebe
opentelemetry-ext-js
js extensions for the open-telemetry project
Stars: ✭ 122 (+139.22%)
Mutual labels:  opentelemetry
gateway
A proxy to buffer and forward metrics, events, and traces.
Stars: ✭ 94 (+84.31%)
Mutual labels:  opentelemetry
worker
Worker for Vela (Target's official Pipeline Automation Framework)
Stars: ✭ 27 (-47.06%)
Mutual labels:  worker
splunk-otel-js-web
Splunk distribution of Open Telemetry for browser environment.
Stars: ✭ 23 (-54.9%)
Mutual labels:  opentelemetry
souls
SOULs 🔥 Build Serverless Apps faster like Rails. Powered by Ruby GraphQL, RBS/Steep, Active Record, RSpec, RuboCop, and Google Cloud.
Stars: ✭ 327 (+541.18%)
Mutual labels:  worker
zeebe-script-worker
Zeebe worker for script evaluation
Stars: ✭ 17 (-66.67%)
Mutual labels:  zeebe
opentelemetry-dotnet-contrib
This repository contains set of components extending functionality of the OpenTelemetry .NET SDK. Instrumentation libraries, exporters, and other components can find their home here.
Stars: ✭ 124 (+143.14%)
Mutual labels:  opentelemetry
msw-storybook-addon
Mock API requests in Storybook with Mock Service Worker.
Stars: ✭ 168 (+229.41%)
Mutual labels:  worker

WorkIt

License: MIT lerna npm

Français

Extensible worker for Node.js that works with both Zeebe and Camunda BPM platforms powered by TypeScript

Motivation

We needed a framework to help us quickly build workers used to execute tasks.

This package can be useful because:

  • Experiment and choose the Camunda platform you want without rewritting the business logic.
  • At this moment, Zeebe doesn't provide all BPMN components. Zeebe is new and some unexpected bugs can appear during development so we can easily revert back to the the former platform if an issue was to rise.
  • Instead of depending directly from a Camunda client, this project provides an abstraction layer. This way it’s easier to change the client or to make your own.
  • You want to have a worker standardization.
  • Uniformisation. Indeed, you can use both platforms depending project needs.
  • Added features like automated tracing.
  • This package enforce feature parity between Zeebe and Camunda BPM through the client libraries. Some features exposed to the Camunda BPM platform are not presents in this package because we couldn't provide them if we switch to Zeebe. This limitation is to guide developers to prepare migration.

Quickstart

Get started in 2 minutes.

Documentation

Packages

Packages will move under @villedemontreal organization after the 4.2.0 version. Packages must be renamed in your package.json file.

For example, instead of workit-camunda it will be @villedemontreal/workit-camunda.

API

Package Description
workit-types This package provides TypeScript interfaces and enums for the Workit core model.
workit-core This package provides default and no-op implementations of the Workit types

Implementation / Clients

Package Description
workit-bpm-client This module provides a full control over the Camunda Bpm platform.
It use camunda-external-task-client-js by default.
workit-zeebe-client This module provides a full control over the Zeebe platform.
It use zeebe-node and zeebe-elasticsearch-client by default.
workit-camunda This module allows you to switch between Camunda BPM and Zeebe easily.
It use workit-bpm-client and workit-zeebe-client by default.

Installing

npm i @villedemontreal/workit-camunda

or using the generator below

Yo!

This generator will help you during your development with this library. It provides handy tools.

npm i -g @villedemontreal/workit-cli

Install a fresh new project

workit init

Generate tasks from your existing BPMN

workit create task --file /your/path.bpmn

Generate new task

workit create task

How to use

Switching between Zeebe and the bpmn platform is easy as specifying a TAG to the IoC.

Run worker

const worker = IoC.get<Worker>(CORE_IDENTIFIER.worker, TAG.camundaBpm); // or TAG.zeebe

worker.start();
worker.run();

Deploy a workflow

const manager = IoC.get<IWorkflowClient>(CORE_IDENTIFIER.client_manager, TAG.camundaBpm); // or TAG.zeebe
const fullpath = `${process.cwd()}/sample/BPMN_DEMO.bpmn`;
await manager.deployWorkflow(fullpath);

Get workflows

Zeebe: You will need elasticsearch instance.

const manager = IoC.get<IWorkflowClient>(CORE_IDENTIFIER.client_manager, TAG.camundaBpm); // or TAG.zeebe
await manager.getWorkflows()

Get a workflow

Zeebe: You will need elasticsearch instance.

const manager = IoC.get<IWorkflowClient>(CORE_IDENTIFIER.client_manager, TAG.camundaBpm); // or TAG.zeebe
await manager.getWorkflow({ bpmnProcessId: "DEMO" });

Update variables

const manager = IoC.get<IWorkflowClient>(CORE_IDENTIFIER.client_manager, TAG.camundaBpm); // or TAG.zeebe
await manager.updateVariables({ 
    processInstanceId: "5c50c48e-4691-11e9-8b8f-0242ac110002",
    variables: { amount: 1000 }
});

Publish message

const manager = IoC.get<IWorkflowClient>(CORE_IDENTIFIER.client_manager, TAG.camundaBpm); // or TAG.zeebe
await manager.publishMessage({
    correlation: {},
    name: "catching",
    variables: { amount: 100 },
    timeToLive: undefined, // only supported for Zeebe
    messageId: "5c50c48e-4691-11e9-8b8f-0242ac110002"
});

Create workflow instance

const manager = IoC.get<IWorkflowClient>(CORE_IDENTIFIER.client_manager, TAG.camundaBpm); // or TAG.zeebe
await manager.createWorkflowInstance({
    bpmnProcessId: "MY_BPMN_KEY",
    variables: {
        hello: "world"
    }
});

Cancel workflow instance

const manager = IoC.get<IWorkflowClient>(CORE_IDENTIFIER.client_manager, TAG.camundaBpm); // or TAG.zeebe
await manager.cancelWorkflowInstance("4651614f-4b3c-11e9-b5b3-ee5801424400");

Resolve incident

const manager = IoC.get<IWorkflowClient>(CORE_IDENTIFIER.client_manager, TAG.camundaBpm); // or TAG.zeebe
await manager.resolveIncident("c84fce6c-518e-11e9-bd78-0242ac110003");

Define tasks (your bpmn activities)

You can define many tasks to one worker. It will handle all messages and will route to the right tasks.

export class HelloWorldTask extends TaskBase<IMessage> {
  // You can type message like IMessage<TBody, TProps> default any
  public execute(message: IMessage): Promise<IMessage> {
      const { properties } = message;
      console.log(`Executing task: ${properties.activityId}`);
      console.log(`${properties.bpmnProcessId}::${properties.processInstanceId} Servus!`);
      // put your business logic here
      return Promise.resolve(message);
  }
}


enum LOCAL_IDENTIFIER {
    // sample_activity must match the activityId in your bpmn
    sample_activity= 'sample_activity'
}

// Register your task
IoC.bindTo(HelloWorldTask, LOCAL_IDENTIFIER.sample_activity);

You can even make complex binding like

IoC.bindTask(HelloWorldTaskV2, LOCAL_IDENTIFIER.activity1, { bpmnProcessId: BPMN_PROCESS_ID, version: 2 });

If you have installed workit-cli, you can do workit create task and everything will be done for you.

Worker life cycle and events

const worker = IoC.get<Worker>(CORE_IDENTIFIER.worker, TAG.zeebe); // or TAG.camundaBpm

worker.once('starting', () => {
    // slack notification 
});

worker.once('stopping', () => {
    // close connections
});

worker.once('stopped', () => {
    // slack notification
});

const handler = worker.getProcessHandler();

handler.on('message', (msg: IMessage) => {
    // log/audit
});

handler.on('message-handled', (err: Error, msg: IMessage) => {
    if (err) {
        // something wrong
    } else {
        // everything is fine
    }
});

worker.start();
worker.run(); // Promise
worker.stop(); // Promise

Interceptors

const workerConfig = {
  interceptors: [
    async (message: IMessage): Promise<IMessage> => {
      // do something before we execute task.
      return message;
    }
  ]
};

IoC.bindToObject(workerConfig, CORE_IDENTIFIER.worker_config);

OpenTelemetry

By default, we bound a NoopTracer but you can provide your own and it must extend Tracer.We strongly recommand to use this kind of pattern in your task: Domain Probe pattern. But here an example:

// Simply bind your custom tracer object like this
IoC.bindToObject(tracer, CORE_IDENTIFIER.tracer);
export class HelloWorldTask extends TaskBase<IMessage> {
  private readonly _tracer: Tracer;
    
  constructor(tracer: Tracer) {
        this._tracer = tracer
  }

  public async execute(message: IMessage): Promise<IMessage> {
      const { properties } = message;
      
      console.log(`Executing task: ${properties.activityId}`);
      console.log(`${properties.bpmnProcessId}::${properties.processInstanceId} Servus!`);

      // This call will be traced automatically
      const response = await axios.get('https://jsonplaceholder.typicode.com/todos/1');
      
      // you can also create a custom trace like this :
      const currentSpan = tracer.getCurrentSpan();
      const span = this._tracer.startSpan('customSpan', {
        parent: currentSpan,
        kind: SpanKind.CLIENT,
        attributes: { key: 'value' },
      });
      
      console.log();
      console.log('data:');
      console.log(response.data);
      // put your business logic here

      // finish the span scope
      span.end();
      
      return Promise.resolve(message);
  }
}

You can look to sample folder where we provide an example (parallel.ts) using Jaeger.

See get started section with OpenTelemetry

Define your config for the platform you want to use

const configBase: ICamundaConfig = {
    workerId: 'demo',
    baseUrl: `__undefined__`,
    topicName: 'topic_demo'
};

// For Camunda BPM platform
const bpmnPlatformClientConfig = { ...configBase, baseUrl: 'http://localhost:8080/engine-rest',  maxTasks: 32, autoPoll: false, use: [] };

IoC.bindToObject(bpmnPlatformClientConfig, CORE_IDENTIFIER.camunda_external_config);

// For Zeebe platform
const zeebeClientConfig = { ...configBase, baseUrl: 'localhost:2650', timeout: 2000 };

// For Zeebe exporter (Elasticsearch instance)
const zeebeElasticExporterConfig = {
    url: `http://localhost:9200`,
};

IoC.bindToObject(zeebeClientConfig, CORE_IDENTIFIER.zeebe_external_config);
IoC.bindToObject(zeebeElasticExporterConfig, CORE_IDENTIFIER.zeebe_elastic_exporter_config)

See documentation

Define your strategies in case of failure or success

By default, we define simple strategy for success or failure. We strongly recommend you to provide yours as your app trigger specific exceptions. Strategies are automatically handled. If an exeption is bubble up from the task, failure strategy is raised, otherwise it's success.

// the idea is to create your own but imagine that your worker works mainly with HTTP REST API
class ServerErrorHandler extends ErrorHandlerBase {
  constructor(config: { maxRetries: number }) {
    super(config);
  }

  public isHandled(error: IErrorResponse<IResponse<IApiError>>): boolean {
    return error.response.status >= 500;
  }
  public handle(error: IErrorResponse<IResponse<IApiError>>, message: IMessage): Failure {
    const retries = this.getRetryValue(message);
    return new Failure(error.message, this.buildErrorDetails(error, message), retries, 2000 * retries);
  }
}

// You got the idea...

// You could create also
// BadRequestErrorHandler
// TimeoutErrorHandler
// UnManagedErrorHandler
// ...
// Then you could build your strategy
/// "FailureStrategy" implements "IFailureStrategy", this interface is provided by workit-camunda
const strategy = new FailureStrategy([
  new AxiosApiErrorHandler(errorConfig, [
    new BadRequestErrorHandler(errorConfig),
    new TimeoutErrorHandler(errorConfig),
    new ServerErrorHandler(errorConfig),
    new UnManagedErrorHandler(errorConfig),
    //...
  ]),
  new ErrorHandler(errorConfig)
]);
// worker will use your new strategy
IoC.bindToObject(strategy, CORE_IDENTIFIER.failure_strategy);

Running the tests

We use Jest.

npm test

Built With

Philosophy

  1. Allow Javascript developers to write code that adheres to the SOLID principles.
  2. Facilitate and encourage the adherence to the best OOP and IoC practices.
  3. Add as little runtime overhead as possible.

Kubernetes

Zeebe

TODO: provide helm chart. But in the meantime, you can do for development:

kubernetes/run

Docker

Zeebe

In your terminal

docker/run

Bpmn platform

docker run -d --name camunda -p 8080:8080 camunda/camunda-bpm-platform:latest
// Go: http://localhost:8080/camunda - user/password : `demo/demo`

More details

TODO

Click to expand
  • Add tests
  • Improve docs
  • Make sample and confirm compatibility with DMN
  • Adding a common exception error codes between Manager clients
  • Add metrics by using prometheus lib

Versionning

We use SemVer for versioning. For the versions available, see the tags on this repository.

workit-* Zeebe Camunda BPM
>=4.0.5 0.22.1 7.6 to latest
3.2.x <=4.0.4 0.20.x < 0.20.1 7.6 to latest
3.1.x 0.20.x < 0.20.1 7.6 to latest
2.2.0 0.20.x < 0.20.1 7.6 to latest
2.1.0 0.19.x 7.6 to latest
2.0.1 0.18.x 7.6 to latest
< 1.0.0 <= 0.17.0 7.6 to latest

Maintainers

See the list of contributors who participated in this project.

Contributing

Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests to us.

License

This project is licensed under the MIT License - see the LICENSE file for details

Acknowledgments

  • Josh Wulf - zeebe-node inspired me during workit-cli development
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].