Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Camunda External Task Testing

bpmn.livemd

Camunda External Task Testing

Mix.install([
  {:req, "~> 0.5.8"},
  {:elixir_uuid, "~> 1.2"}
])

Setup

process_key = "external_task_simulation"
topic_possibilities = ["elixir", "python", "java", "go", "rust"]
worker_id = "livebook-#{UUID.uuid4()}"
num_of_processes = 5_000

handled_topics =
  Enum.map(["elixir", "python", "java", "go", "rust"], fn topic ->
    %{topicName: topic, lockDuration: System.convert_time_unit(30, :second, :millisecond)}
  end)
req =
  Req.new(
    base_url: "http://localhost:8080/engine-rest",
    auth: {:basic, "demo:demo"}
  )

:ok

Start Processes

Task.async_stream(1..num_of_processes, fn _i ->
  Req.post!(req,
    url: "/process-definition/key/#{process_key}/start",
    json: %{
      businessKey: UUID.uuid4(),
      variables: %{
        topics: %{
          value: Enum.take_random(topic_possibilities, 3)
        }
      }
    }
  )
end)
|> Enum.map(fn {:ok, %{status: status}} -> status end)
|> Enum.group_by(fn x -> x end)
|> Enum.map(fn {k, v} -> {k, Enum.count(v)} end)
|> Enum.into(%{})

Fetch some external task

Randomly do one of 3 actions: complete, fail or bpmn error

Req.post!(req,
  url: "/external-task/fetchAndLock",
  json: %{
    workerId: worker_id,
    maxTasks: 20_000,
    usePriority: false,
    topics: handled_topics
  }
).body
|> Enum.map(fn %{"id" => id} -> id end)
|> Task.async_stream(fn id ->
  action =
    case :rand.uniform(100) do
      x when x in 1..85 -> :complete
      100 -> :error
      _x -> :failure
    end

  result =
    case action do
      :complete ->
        Req.post!(req,
          url: "external-task/#{id}/complete",
          json: %{
            workerId: worker_id,
            variables: %{
              doneBy: %{value: worker_id}
            }
          }
        ).status

      :failure ->
        Req.post!(req,
          url: "external-task/#{id}/failure",
          json: %{
            workerId: worker_id,
            errorMessage: "Because I said so",
            retries: 10,
            retryTimeout: System.convert_time_unit(5, :second, :millisecond)
          }
        ).status

      :error ->
        Req.post!(req,
          url: "external-task/#{id}/bpmnError",
          json: %{
            workerId: worker_id,
            errorCode: "livebook-error"
          }
        ).status
    end

  {id, action, result}
end)
|> Enum.filter(fn {:ok, {_, _, status}} -> status == 204 end)
|> Enum.group_by(fn {:ok, {_, action, _}} -> action end)
|> Enum.map(fn {k, v} -> {k, Enum.count(v)} end)
|> Enum.into(%{})