Current section

86 Versions

Jump to

Compare versions

5 files changed
+101 additions
-13 deletions
  @@ -1,6 +1,6 @@
1 1 {<<"links">>,[{<<"GitHub">>,<<"https://github.com/CharlesIrvineKC/mozart">>}]}.
2 2 {<<"name">>,<<"mozart">>}.
3 - {<<"version">>,<<"0.6.5">>}.
3 + {<<"version">>,<<"0.6.6">>}.
4 4 {<<"description">>,
5 5 <<"Mozart is a BPM platform written in Elixir. It is currently in active development,\nbut it has sufficient functionality for the development of BPM POCs.">>}.
6 6 {<<"elixir">>,<<"~> 1.16">>}.
  @@ -56,12 +56,12 @@
56 56 <<"lib/mozart/task/send.ex">>,<<"lib/mozart/task/timer.ex">>,
57 57 <<"lib/mozart/task/subprocess.ex">>,<<"lib/mozart/task/join.ex">>,
58 58 <<"lib/mozart/task/user.ex">>,<<"lib/mozart/task/service.ex">>,
59 - <<"lib/mozart/task/receive.ex">>,<<"lib/mozart/task/prototype.ex">>,
60 - <<"lib/mozart/task/parallel.ex">>,<<"lib/mozart/task/rule.ex">>,
61 - <<"lib/mozart/task/repeat.ex">>,<<"lib/mozart/task/case.ex">>,
62 - <<"lib/mozart/task/reroute.ex">>,<<"lib/mozart/process_engine.ex">>,
63 - <<"lib/mozart/application.ex">>,<<"lib/mozart/data">>,
64 - <<"lib/mozart/data/bpm_application.ex">>,
59 + <<"lib/mozart/task/receive.ex">>,<<"lib/mozart/task/conditional.ex">>,
60 + <<"lib/mozart/task/prototype.ex">>,<<"lib/mozart/task/parallel.ex">>,
61 + <<"lib/mozart/task/rule.ex">>,<<"lib/mozart/task/repeat.ex">>,
62 + <<"lib/mozart/task/case.ex">>,<<"lib/mozart/task/reroute.ex">>,
63 + <<"lib/mozart/process_engine.ex">>,<<"lib/mozart/application.ex">>,
64 + <<"lib/mozart/data">>,<<"lib/mozart/data/bpm_application.ex">>,
65 65 <<"lib/mozart/data/process_model.ex">>,
66 66 <<"lib/mozart/data/process_state.ex">>,<<"lib/mozart/event">>,
67 67 <<"lib/mozart/event/task_exit.ex">>,<<".formatter.exs">>,<<"mix.exs">>,
  @@ -11,6 +11,7 @@ defmodule Mozart.BpmProcess do
11 11 end
12 12 ```
13 13 """
14 + alias Mozart.Task.Conditional
14 15 alias Mozart.Task.Service
15 16 alias Mozart.Task.User
16 17 alias Mozart.Task.Subprocess
  @@ -24,6 +25,7 @@ defmodule Mozart.BpmProcess do
24 25 alias Mozart.Task.Prototype
25 26 alias Mozart.Task.Repeat
26 27 alias Mozart.Task.Reroute
28 + alias Mozart.Task.Conditional
27 29
28 30 alias Mozart.Type.Choice
29 31 alias Mozart.Type.MultiChoice
  @@ -282,6 +284,26 @@ defmodule Mozart.BpmProcess do
282 284 end
283 285 end
284 286
287 + defmacro conditional_task(name, options, do: tasks) do
288 + quote do
289 + options = unquote(options)
290 + condition = Keyword.get(options, :condition)
291 + module = Keyword.get(options, :module) || __MODULE__
292 + c_task = %Conditional{name: unquote(name), condition: condition, module: module}
293 + insert_new_task(c_task)
294 + @capture_subtasks true
295 + unquote(tasks)
296 + @subtasks set_next_tasks(@subtasks)
297 + first = List.first(@subtasks)
298 + last = List.last(@subtasks)
299 + c_task = Map.put(c_task, :first, first.name) |> Map.put(:last, last.name)
300 + @tasks Enum.map(@tasks, fn t -> if t.name == unquote(name), do: c_task, else: t end)
301 + @subtask_sets [@subtasks | @subtask_sets]
302 + @subtasks []
303 + @capture_subtasks false
304 + end
305 + end
306 +
285 307 @doc """
286 308 Used to define one of many parallel execution paths within a parallel task. Arguments are a task name a block of tasks.
  @@ -328,7 +328,7 @@ defmodule Mozart.ProcessEngine do
328 328 complete_on_task_exit_event(task.subprocess_pid)
329 329 end
330 330
331 - # Todo: Code exit repeat task
331 + # TODO: Code exit repeat task
332 332
333 333 update_completed_task_state(state, task, event.next) |> execute_process()
334 334 end
  @@ -384,13 +384,33 @@ defmodule Mozart.ProcessEngine do
384 384 state =
385 385 Map.put(state, :open_tasks, Map.put(state.open_tasks, new_task.uid, new_task))
386 386
387 - if new_task.type == :repeat do
388 - trigger_repeat_execution(state, new_task)
387 + state =
388 + if new_task.type == :repeat do
389 + trigger_repeat_execution(state, new_task)
390 + else
391 + state
392 + end
393 +
394 + if new_task.type == :conditional do
395 + trigger_conditional_execution(state, new_task)
389 396 else
390 397 state
391 398 end
392 399 end
393 400
401 + defp trigger_conditional_execution(state, new_task) do
402 + if apply(new_task.module, new_task.condition, [state.data]) do
403 + first_task = get_new_task_instance(new_task.first, state)
404 + Logger.info("New #{first_task.type} task instance [#{first_task.name}][#{first_task.uid}]")
405 + state = Map.put(state, :open_tasks, Map.put(state.open_tasks, first_task.uid, first_task))
406 + do_new_task_side_effects(first_task.type, first_task, state)
407 + else
408 + new_task = Map.put(new_task, :complete, true)
409 + open_tasks = Map.put(state.open_tasks, new_task.uid, new_task)
410 + Map.put(state, :open_tasks, open_tasks)
411 + end
412 + end
413 +
394 414 defp trigger_repeat_execution(state, new_task) do
395 415 if apply(new_task.module, new_task.condition, [state.data]) do
396 416 first_task = get_new_task_instance(new_task.first, state)
  @@ -503,19 +523,37 @@ defmodule Mozart.ProcessEngine do
503 523 |> Map.put(:open_tasks, open_tasks)
504 524 |> Map.put(:completed_tasks, completed_tasks)
505 525 |> check_for_repeat_task_completion(task)
526 + |> check_for_conditional_task_completion(task)
506 527 end
507 528
508 529 defp check_for_repeat_task_completion(state, task) do
509 - r_task = find_by_last_task(state, task.name)
530 + r_task = find_repeat_task_by_last_task(state, task.name)
510 531 if r_task, do: trigger_repeat_execution(state, r_task), else: state
511 532 end
512 533
513 - defp find_by_last_task(state, task_name) do
534 + defp check_for_conditional_task_completion(state, task) do
535 + c_task = find_conditional_task_by_last_task(state, task.name)
536 + if c_task do
537 + c_task = Map.put(c_task, :complete, true)
538 + open_tasks = Map.put(state.open_tasks, c_task.uid, c_task)
539 + Map.put(state, :open_tasks, open_tasks)
540 + else
541 + state
542 + end
543 + end
544 +
545 + defp find_repeat_task_by_last_task(state, task_name) do
514 546 Enum.find_value(state.open_tasks, fn {_key, t} ->
515 547 if t.type == :repeat && t.last == task_name, do: t
516 548 end)
517 549 end
518 550
551 + defp find_conditional_task_by_last_task(state, task_name) do
552 + Enum.find_value(state.open_tasks, fn {_key, t} ->
553 + if t.type == :conditional && t.last == task_name, do: t
554 + end)
555 + end
556 +
519 557 defp update_completed_task_state(state, task, next_task) do
520 558 state = update_for_completed_task(state, task)
521 559 if next_task, do: create_next_tasks(state, next_task, task.name), else: state
  @@ -547,6 +585,11 @@ defmodule Mozart.ProcessEngine do
547 585 update_completed_task_state(state, task, task.next) |> execute_process()
548 586 end
549 587
588 + defp complete_conditional_task(state, task) do
589 + Logger.info("Complete conditional task [#{task.name}]")
590 + update_completed_task_state(state, task, task.next) |> execute_process()
591 + end
592 +
550 593 defp complete_service_task(state, task) do
551 594 Logger.info("Complete service task [#{task.name}[#{task.uid}]")
552 595
  @@ -729,6 +772,9 @@ defmodule Mozart.ProcessEngine do
729 772 complete_able_task.type == :repeat ->
730 773 complete_repeat_task(state, complete_able_task)
731 774
775 + complete_able_task.type == :conditional ->
776 + complete_conditional_task(state, complete_able_task)
777 +
732 778 complete_able_task.type == :reroute ->
733 779 complete_reroute_task(state, complete_able_task)
734 780 end
  @@ -772,5 +818,6 @@ defmodule Mozart.ProcessEngine do
772 818 defp complete_able(t) when t.type == :join, do: t.inputs == []
773 819 defp complete_able(t) when t.type == :user, do: t.complete
774 820 defp complete_able(t) when t.type == :repeat, do: t.complete
821 + defp complete_able(t) when t.type == :conditional, do: t.complete
775 822 defp complete_able(t) when t.type == :prototype, do: true
776 823 end
  @@ -0,0 +1,19 @@
1 + defmodule Mozart.Task.Conditional do
2 + @moduledoc false
3 + defstruct [
4 + :name,
5 + :next,
6 + :uid,
7 + :model,
8 + :condition,
9 + :module,
10 + :first,
11 + :last,
12 + :start_time,
13 + :finish_time,
14 + :duration,
15 + :process_uid,
16 + complete: false,
17 + type: :conditional
18 + ]
19 + end
  @@ -4,7 +4,7 @@ defmodule Mozart.MixProject do
4 4 def project do
5 5 [
6 6 app: :mozart,
7 - version: "0.6.5",
7 + version: "0.6.6",
8 8 elixir: "~> 1.16",
9 9 elixirc_paths: ["lib", "test/support"],
10 10 start_permanent: Mix.env() == :prod,