Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

robocorp client #1

Merged
merged 16 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 30 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,31 @@
name: External Worker Build and Test
name: Flowable External Client Build and Test

on: [push, pull_request]

jobs:
build:
test-external-worker-client:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.12.0"]

steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Display Python version
run: python -c "import sys; print(sys.version)"
- run: pip install virtualenv
- run: virtualenv venv
- run: source venv/bin/activate
- run: pip install setuptools
- run: pip install -e ".[testing]"
working-directory: ./external-worker/
- run: python -m unittest discover
working-directory: ./external-worker/
test-robocorp-client:
runs-on: ubuntu-latest
strategy:
matrix:
Expand All @@ -22,4 +43,10 @@ jobs:
- run: virtualenv venv
- run: source venv/bin/activate
- run: pip install setuptools
- run: python setup.py pytest
- run: python setup.py install
working-directory: ./external-worker/
- run: pip install -e ".[testing]"
working-directory: ./robocorp/
- run: cp -a external-worker/flowable/external_worker_client robocorp/flowable/ # we need to copy this module over, since it's only searching locally for modules
- run: python -m unittest discover
working-directory: ./robocorp/
31 changes: 30 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,38 @@ jobs:
- run: source venv/bin/activate
- run: pip install setuptools
- run: python setup.py sdist
working-directory: ./external-worker/
- run: pip wheel --no-deps . -w dist
working-directory: ./external-worker/
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: dist/
packages-dir: external-worker/dist/
verbose: true

build-robocorp-client:
runs-on: ubuntu-latest
environment: release
permissions:
id-token: write
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.12.0
uses: actions/setup-python@v4
with:
python-version: 3.12.0
- name: Display Python version
run: python -c "import sys; print(sys.version)"
- run: pip install virtualenv
- run: virtualenv venv
- run: source venv/bin/activate
- run: pip install setuptools
- run: python setup.py sdist
working-directory: ./robocorp/
- run: pip wheel --no-deps . -w dist
working-directory: ./robocorp/
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: robocorp/dist/
verbose: true
34 changes: 32 additions & 2 deletions .github/workflows/test-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
- v*

jobs:
build:
build-external-worker-client:
runs-on: ubuntu-latest
environment: release
permissions:
Expand All @@ -24,10 +24,40 @@ jobs:
- run: source venv/bin/activate
- run: pip install setuptools
- run: python setup.py sdist
working-directory: ./external-worker/
- run: pip wheel --no-deps . -w dist
working-directory: ./external-worker/
- name: Publish package distributions to Test PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
packages-dir: dist/
packages-dir: external-worker/dist/
verbose: true

build-robocorp-client:
runs-on: ubuntu-latest
environment: release
permissions:
id-token: write
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.12.0
uses: actions/setup-python@v4
with:
python-version: 3.12.0
- name: Display Python version
run: python -c "import sys; print(sys.version)"
- run: pip install virtualenv
- run: virtualenv venv
- run: source venv/bin/activate
- run: pip install setuptools
- run: python setup.py sdist
working-directory: ./robocorp/
- run: pip wheel --no-deps . -w dist
working-directory: ./robocorp/
- name: Publish package distributions to Test PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
packages-dir: robocorp/dist/
verbose: true
66 changes: 5 additions & 61 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,68 +1,12 @@
# Flowable External Worker Library for Python

# Flowable External Client Python

[License:
![license](https://img.shields.io/hexpm/l/plug.svg)](https://github.com/flowable/flowable-external-client-python/blob/main/LICENSE)

![Flowable Actions CI](https://github.com/flowable/flowable-external-client-python/actions/workflows/main.yml/badge.svg?branch=main)

An _External Worker Task_ in BPMN or CMMN is a task where the custom logic of that task is executed externally to Flowable, i.e. on another server.
When the process or case engine arrives at such a task, it will create an **external job**, which is exposed over the REST API.
Through this REST API, the job can be acquired and locked.
Once locked, the custom logic is responsible for signalling over REST that the work is done and the process or case can continue.

This project makes implementing such custom logic in Python easy by not having the worry about the low-level details of the REST API and focus on the actual custom business logic.
Integrations for other languages are available, too.

## Authentication

The different ways to authenticate are explained in the [documentation of the underlying requests HTTP library which is used to connect to Flowable](https://requests.readthedocs.io/en/latest/user/authentication/).
The `ExternalWorkerClient` accepts as a parameter `auth` an implementation of `requests.auth.AuthBase`.
There are default implementations for example for basic authentication e.g. `HTTPBasicAuth("admin", "test")`.
Flowable offers a bearer token implementation `FlowableCloudToken` which allows to specify an access token to the Flowable Cloud offering.

## Installation

To install the external worker library, execute the following command:

```
pip install flowable.external-worker-client
```

## Sample

### Cloud

The usage with Flowable Cloud is simpler, since everything is pre-configured.
However, it's required to either use the user credentials or to pre-configure a personal access token.

```python
from flowable.external_worker_client import ExternalWorkerClient
from flowable.external_worker_client.cloud_token import FlowableCloudToken

client = ExternalWorkerClient(auth=FlowableCloudToken("<personal-access-token>"))

def my_callback(job, worker_result_builder):
print('Executed job: ' + job.id)
return worker_result_builder.success()

subscription = client.subscribe('myTopic', my_callback)
```

### Local

The following is an example how you can connect to a Flowable instance running at `http://localhost:8090` and process all messages retrieved on the topic `myTopic`:

```python
from flowable.external_worker_client import ExternalWorkerClient
from requests.auth import HTTPBasicAuth

client = ExternalWorkerClient('http://localhost:8090/flowable-work', auth=HTTPBasicAuth("admin", "test"))

def my_callback(job, worker_result_builder):
print('Executed job: ' + job.id)
return worker_result_builder.success()

subscription = client.subscribe('myTopic', my_callback)
```
This is a collection of multiple Flowable Python clients.
Currently, the project consists out of:

* [External Worker Client](./external-worker): A library to connect custom application code to Flowable with the external worker functionality
* [Robocorp Client](./robocorp-client): A python module to execute Robocorp actions and tasks with the Flowable Robocorp task (based on the external worker).
67 changes: 67 additions & 0 deletions external-worker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Flowable External Worker Library for Python


[License:
![license](https://img.shields.io/hexpm/l/plug.svg)](https://github.com/flowable/flowable-external-client-python/blob/main/LICENSE)

![Flowable Actions CI](https://github.com/flowable/flowable-external-client-python/actions/workflows/main.yml/badge.svg?branch=main)

An _External Worker Task_ in BPMN or CMMN is a task where the custom logic of that task is executed externally to Flowable, i.e. on another server.
When the process or case engine arrives at such a task, it will create an **external job**, which is exposed over the REST API.
Through this REST API, the job can be acquired and locked.
Once locked, the custom logic is responsible for signalling over REST that the work is done and the process or case can continue.

This project makes implementing such custom logic in Python easy by not having the worry about the low-level details of the REST API and focus on the actual custom business logic.
Integrations for other languages are available, too.

## Authentication

The different ways to authenticate are explained in the [documentation of the underlying requests HTTP library which is used to connect to Flowable](https://requests.readthedocs.io/en/latest/user/authentication/).
The `ExternalWorkerClient` accepts as a parameter `auth` an implementation of `requests.auth.AuthBase`.
There are default implementations for example for basic authentication e.g. `HTTPBasicAuth("admin", "test")`.
Flowable offers a bearer token implementation `FlowableCloudToken` which allows to specify an access token to the Flowable Cloud offering.

## Installation

To install the external worker library, execute the following command:

```
pip install flowable.external-worker-client
```

## Sample

### Cloud

The usage with Flowable Cloud is simpler, since everything is pre-configured.
However, it's required to either use the user credentials or to pre-configure a personal access token.

```python
from flowable.external_worker_client import ExternalWorkerClient
from flowable.external_worker_client.cloud_token import FlowableCloudToken

client = ExternalWorkerClient(auth=FlowableCloudToken("<personal-access-token>"))

def my_callback(job, worker_result_builder):
print('Executed job: ' + job.id)
return worker_result_builder.success()

subscription = client.subscribe('myTopic', my_callback)
```

### Local

The following is an example how you can connect to a Flowable instance running at `http://localhost:8090` and process all messages retrieved on the topic `myTopic`:

```python
from flowable.external_worker_client import ExternalWorkerClient
from requests.auth import HTTPBasicAuth

client = ExternalWorkerClient('http://localhost:8090/flowable-work', auth=HTTPBasicAuth("admin", "test"))

def my_callback(job, worker_result_builder):
print('Executed job: ' + job.id)
return worker_result_builder.success()

subscription = client.subscribe('myTopic', my_callback)
```
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import sys
import threading
import time
from os import getpid
Expand Down Expand Up @@ -52,7 +53,7 @@ class ExternalWorkerClient(object):

def __init__(
self,
flowable_host: str = "https://cloud.flowable.com/work",
flowable_host: str = "https://trial.flowable.com/work",
worker_id: str = None,
auth: AuthBase = None,
customize_session: Callable[[Session], None] = lambda session: None
Expand Down Expand Up @@ -103,5 +104,7 @@ def _consume(
result.execute(self._restClient)
else:
self._restClient.complete_job(job.id)
except:
self._restClient.fail_job(job.id)
except Exception as e:
print("An error occurred during job execution " + job.id, file=sys.stderr)
print(e, file=sys.stderr)
self._restClient.fail_job(job.id, e.__str__())
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def acquire_jobs(
}
)
if r.status_code != 200:
print(r.text)
raise FlowableRestException(r.status_code, r.text)

return list(map(response_converter.convert_to_external_worker_acquire_job_response, r.json()))
Expand Down
14 changes: 7 additions & 7 deletions setup.py → external-worker/setup.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
from setuptools import find_packages, setup

# read the contents of your README file
from pathlib import Path

from setuptools import setup

this_directory = Path(__file__).parent
long_description = (this_directory / "README.md").read_text()

setup(
name='flowable.external-worker-client',
packages=['flowable', 'flowable.external_worker_client'],
version='1.0.0',
version='1.0.1rc1',
description='Flowable External Worker Library to connect Python code to Flowable using an external worker.',
long_description=long_description,
long_description_content_type='text/markdown',
author='Flowable',
license='',
license='Apache License, Version 2.0',
install_requires=['requests>=2.27.0'],
setup_requires=['pytest-runner'],
tests_require=['pytest', 'vcrpy'],
test_suite='tests',
extras_require={
'testing': ['pytest', 'vcrpy']
},
)
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading
Loading