Service Task supported Implementation: Script?

Updated for clarity:

A service task can currently be used with connectors, and one of the default connectors is the http-connector that leverages the Apache HTTP client.

To configure a http-connector in a service task we use the Input/Output mappings, primarily: url, headers, method, payload, response.

We can use scripts in each of these input/output mappings as @Webcyberrob mentions below.

Asking two questions:

  1. Can a service task that is using http-connector use a single script to configure the http-connector? (at least for the the inputs).

  2. Can the http-connector be accessed/used through a script? Use Case: Similar to how we can use Java classes to pretty much do whatever we need, can we use a Script to access http-connector so that we can preform more fine grained and robust logic: such as multiple web service calls wrapped in a single service task, layering of error handling, etc. We have lots of options for executing java classes and the power that comes with those classes, having access to use http-connector in a script opens a lot of options.

Hi Stephen,

Im a bit puzzled by your comment. From my perspective, a script task has the same semantics as a service task, however its intent is to run either an inline or external script.

In addition, the connectors can be manipulated through script. Hence with a script task (and even a service task), you should have very fine control if you need it…

regards

Rob

2 Likes

@Webcyberrob
I have updated the original question for clarity.

TLDR: Agree that you can manipulate connector input and outputs mappings with scripts. But the question is, can you configure a connector through a single script?
The docs show examples of stand-alone usage such as:

https://docs.camunda.org/manual/7.6/reference/connect/http-connector/

http.createRequest()
  .post()
  .url("http://camunda.org")
  .contentType("text/plain")
  .payload("Hello World!")
  .execute();

Could the above example be done through a single script that accesses http-connectors api?

Also not sure if there was confusion based on your comment. In all references to script, I am not referring to a Script Task.

Hi @StephenOTT,

do I understand your question properly?

Given that underlying implementation of http-connector is based on Apache HTTP Client, I would like to perform configuration of client once and share it to send multiple requests.

Cheers,
Askar

@aakhmerov that could be one use case.

Basically If there was a way to have a single input mapping that would allow you to call a script that would configure all of the http-connector configuration variables, and the ability to control execution of the HTTP request.

Another scenario similar to yours would be: Creating a external script with multiple variables of configurations for service tasks that could be reused in many different scenarios; having the ability to call the specific function in that external script, and that function configures all of the variables of the http-connector (url, method, headers, payload, etc, and maybe response as well). This lets us configure a service task that uses the http-connector much more quickly. If we were using Java Classes, we would essentially be doing the same thing, but in this case i am looking for a way to do it just using scripts.

edit: Maybe a more simple way to approach this would be: Imagine there was not Service Task, and we only had Script Tasks: is there a way to call/execute Http-Connector/HTTP-Client from Script Task? Now imagine that same ability could be used to configure a Service Task so we have the proper BPMN element usage.

@StephenOTT,

we are about to get really theoretical now I’m afraid :slight_smile: Additionally I would assume that we are talking about groovy scripts. In this case, any script is not different from any other java code and can execute other scripts (in your case performing some set-up steps). Would look something like http://stackoverflow.com/questions/9136328/including-a-groovy-script-in-another-groovy. Now if you do that, you would be able to isolate your setup code in a separate script, which is not much different from declaring some class with static java method that does set-up somewhere on your classpath, and then invoking that set-up method from your groovy script.

So if your question is about isolation of concerns, then it’s rather easy to achieve. If the question is about number of times some set-up code would be executed, the same rules would apply as to passing objects between tasks. I.e. you would do setup once, put resulting client in variable and pass it along to next task, or somehow close to that. Not the most elegant way if you ask me.

Does that help you?
Askar.

Groovy could be a use case for sure. JS i prefer more in this scenario as load(path or url to js file); works very well.

The initial want for the mentioned “feature” is to ease set-up time when there are large number of service tasks with very similar usage. Element Templates in the modeller are not currently available for connectors, and this would likely help. But we also started looking at ways to quickly copy and paste scripts which are the configuration (of course we could copy the xml, but this is very error prone).

Now if you do that, you would be able to isolate your setup code in a separate script, which is not much different from declaring some class with static java method that does set-up somewhere on your classpath, and then invoking that set-up method from your groovy script.

@aakhmerov
With JS and nashorns load(); function, the need to deploy a java file becomes less needed. If the http client could be access/configured through a script, then configuring a http-connector could be a single Input mapping, or just a Service Tasks different implementation of “Script” that provides access to Connectors.

For example you can easily load underscore and manipulate json such as:

load("https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js");

var list1 = [{title: "Cymbeline", author: "Shakespeare", year: 1711}, {title: "Cymbeline", author: "Shakespeare", year: 1611}, {title: "The Tempest", author: "Shakespeare", year: 1611}]

_.where(list1, {author: "Shakespeare", year: 1611});

Hi @StephenOTT,

sounds fine to me, but now I am lost, what is the question? :slight_smile:

Cheers,
Askar

@aakhmerov: still the same overall questions:

  1. Can a service task that is using http-connector use a single script to configure the http-connector? (at least for the the inputs).

  2. Can the http-connector be accessed/used through a script? (does not have to be a script task)

Hi Stephen,

Can a service task that is using http-connector use a single script to configure the http-connector? (at least for the the inputs).

If I understood what you want I would suggest to you create a delegate that does the http request for you.
Then you pass the relevant parameters through field injection.

I think this is the best way to get something really customised that does whatever you want. Also properly error handling using the http-connector directly in the model is a pain in the ass.

(I know I did not answer your question, actually I was asking myself the same thing, but I think it’s not possible, at least I did not found any example doing so)

Cheers,
Felipe

hah yes agreed :slight_smile:

Hi @StephenOTT

could you check if I understand your questions correctly please

Q1: can I define connector input inside my .bpmn file as following?
<camunda:inputParameter name="in"> <camunda:script scriptFormat="groovy" resource="org/camunda/bpm/engine/test/bpmn/executionlistener/executionListener.groovy"/> </camunda:inputParameter>

and configure url, method etc. in that script

Q2: can I access specific connector instance during runtime from my scripts?

Cheers,
Askar

Yes. (Does not have to be a Input Parameter. My other thought was that a Service Task could have a “implementation” option of “Script” and you could access connectors or the raw httpclient similar to execution.

Hey Guys,

Also properly error handling using the http-connector directly in the model is a pain in the ass.

I’m courious, did you try something like this process (Task Check field length) with this script?

Thanks, Ingo

Hi @Ingo_Richtsmeier,

Thanks for the example! I will give my personal opinion around it, please let me know if I’m saying something wrong :grin:

  • If I want to check if the output status is 200 or 201 for every response, but each one will have specific parsing after the status checking, I’ll need to replicate the status checking for every single script right?

  • A more problematic one is If the url does not exists, or it’s offline for some reason … because the error boundary will not be executed. Then we have 2 options that in my opinion both are bad:
    1- mark it as async before and then it will rises an incident.
    2- let it rollback (I open an topic here around other thing related to that, because even if the previous task has a timer boundary configured as a cycle, after the rollback the event will not be triggered anymore).

So for me error handling when using the http-connector in the model, is not something easy to manage when you really want to understand what is going on… that is why I suggest the creation of a delegate to better handle it.

Cheers,
Felipe

Hi @Felipe,

in my opinion error handling with connector is as powerful as error handling with java delegates.

If you differentiate between business- and technical errors, you should use the bpmn-error for the business errors, where a user (or a service) is able to repair the state of the process himself, i.e. correct an adress or other process data before the process loops into a retry of the service call. (I didn’t model this in my example)

With an incident the engine stops executing the process instance, saves the stacktrace in the cockpit and an admin can inspect it, repair the environment and proceed the process. This should be used for all unexpected issues like an unexisting url or an unreachable service.

So you should mark all business errors with error boundary events and throw the BpmnError here and mark the service tasks with async to transform technical errors into incidents to give an admin the chance to repair and proceed. Either for connectors or delegates.

Incidents are not bad if the user has no chance to repair the service call to fulfill his work on a task. They are better than a rollback.

Cheers, Ingo

Hi @StephenOTT,

right now you cannot do that. Just gave it a try in a unit test. You only have access to execution in that scope right now.

Cheers,
Askar

cross reference for future ref: Replacing Http-Connector with Jsoup usage