Packages
step_flow
1.8.1
1.9.0-rc2
1.9.0-rc1
1.9.0-rc0
1.8.2
1.8.1
1.8.1-rc8
1.8.1-rc7
1.8.1-rc6
1.8.1-rc5
1.8.1-rc4
1.8.1-rc3
1.8.1-rc2
1.8.1-rc1
1.8.1-rc0
1.8.0
1.8.0-rc3
1.8.0-rc2
1.8.0-rc1
1.8.0-rc0
1.7.3
1.7.3-rc4
1.7.3-rc3
1.7.3-rc2
1.7.3-rc1
1.7.3-rc0
1.7.2
1.7.2-rc4
1.7.2-rc3
1.7.2-rc2
1.7.2-rc1
1.7.2-rc0
1.7.1
1.7.0
1.7.0-rc1
1.7.0-rc0
1.6.1
1.6.1-rc1
1.6.1-rc0
1.6.0
1.6.0-rc9
1.6.0-rc8
1.6.0-rc7
1.6.0-rc6
1.6.0-rc5
1.6.0-rc4
1.6.0-rc3
1.6.0-rc20
1.6.0-rc2
1.6.0-rc19
1.6.0-rc18
1.6.0-rc17
1.6.0-rc16
1.6.0-rc15
1.6.0-rc14
1.6.0-rc13
1.6.0-rc12
1.6.0-rc11
1.6.0-rc10
1.6.0-rc1
1.5.0
1.5.0-rc1
1.4.2-rc2
1.4.2-rc1
1.4.1
1.4.1-rc1
1.4.0
1.4.0-rc4
1.4.0-rc3
1.4.0-rc2
1.4.0-rc1
1.3.1
1.3.0
1.3.0-rc
1.2.0
1.1.0
1.0.0
1.0.0-rc9
1.0.0-rc8
1.0.0-rc7
1.0.0-rc6
1.0.0-rc5
1.0.0-rc1
0.2.13
0.2.12
0.2.11
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
0.0.24
0.0.23
0.0.22
0.0.21
0.0.20
0.0.19
0.0.18
0.0.17
0.0.16
0.0.15
0.0.14
0.0.13
0.0.12
0.0.11
0.0.10
0.0.9
0.0.8
0.0.7
0.0.6
0.0.4
0.0.3
0.0.2
0.0.1
Step flow manager for Elixir applications
Current section
Files
Jump to
Current section
Files
lib/step_flow/controllers/workflows.ex
defmodule StepFlow.Controllers.Workflows do
@moduledoc false
require Logger
alias StepFlow.Controllers.Jobs
alias StepFlow.Controllers.Progressions
@doc """
Returns an attribute map to have a workflow configuration.
"""
def get_attr(workflow) do
%{
schema_version: workflow.schema_version,
identifier: workflow.identifier,
version_major: workflow.version_major,
version_minor: workflow.version_minor,
version_micro: workflow.version_micro,
tags: workflow.tags,
is_live: workflow.is_live,
deleted: workflow.deleted,
notification_hooks:
Enum.map(workflow.notification_hooks, fn x -> Map.drop(x, ["status"]) end),
reference: workflow.reference,
user_uuid: workflow.user_uuid,
steps: Enum.map(workflow.steps, fn x -> Map.drop(x, [:jobs, :status, "started"]) end),
start_parameters: workflow.start_parameters,
parameters: workflow.parameters
}
end
def get_steps_with_status(steps, workflow_jobs, result \\ [])
def get_steps_with_status([], _workflow_jobs, result), do: result
def get_steps_with_status(nil, _workflow_jobs, result), do: result
def get_steps_with_status([step | steps], workflow_jobs, result) do
name = StepFlow.Map.get_by_key_or_atom(step, :name)
step_id = StepFlow.Map.get_by_key_or_atom(step, :id)
jobs =
workflow_jobs
|> Enum.filter(fn job -> job.name == name && job.step_id == step_id end)
job_status = count_step_jobs_status(jobs)
status = get_step_status_from_job_status(job_status)
step =
step
|> Map.put(:status, status)
|> Map.put(:jobs, job_status)
result = List.insert_at(result, -1, step)
get_steps_with_status(steps, workflow_jobs, result)
end
defp get_step_status_from_job_status(job_status) do
cond do
job_status.errors > 0 ->
:error
is_still_processing(job_status) ->
:processing
job_status.stopped > 0 ->
:stopped
job_status.paused > 0 ->
:paused
is_skipped(job_status) ->
:skipped
is_completed(job_status) ->
:completed
true ->
:pending
end
end
def update_step(workflow, step, key, value) do
workflow = StepFlow.Workflows.get_workflow!(workflow.id)
steps =
get_attr(workflow).steps
|> Enum.map(fn s ->
if StepFlow.Map.get_by_key_or_atom(s, :id) == StepFlow.Map.get_by_key_or_atom(step, :id) do
Map.put(s, key, value)
else
s
end
end)
StepFlow.Workflows.update_workflow(workflow, %{steps: steps})
end
defp count_step_jobs_status(jobs) do
completed = count_status(jobs, :completed)
errors = count_status(jobs, :error)
skipped = count_status(jobs, :skipped)
stopped = count_status(jobs, :stopped)
processing = count_status(jobs, :processing)
paused = count_status(jobs, :paused)
queued = count_status(jobs, :queued)
dropped = count_status(jobs, :dropped)
%{
total: length(jobs) - dropped,
completed: completed,
dropped: dropped,
errors: errors,
paused: paused,
processing: processing,
queued: queued,
skipped: skipped,
stopped: stopped
}
end
defp count_status(jobs, status, count \\ 0)
defp count_status([], _status, count), do: count
defp count_status([job | jobs], status, count) do
count_completed =
job.status
|> Enum.filter(fn s -> s.state == :completed end)
|> length
# A job with at least one status.state at :completed is considered :completed
count =
if count_completed >= 1 do
if status == :completed do
count + 1
else
count
end
else
count_uncompleted_status(status, job, count)
end
count_status(jobs, status, count)
end
defp count_uncompleted_status(status, job, count) do
if status in [:processing, :error, :paused, :skipped, :stopped, :queued, :dropped, :completed] do
count_for_status(job, count, status)
else
raise RuntimeError
Logger.error("unreachable")
count
end
end
defp count_for_status(_job, count, :completed), do: count
defp count_for_status(job, count, :processing) do
if job.progressions == [] do
count
else
last_progression =
job.progressions
|> Progressions.get_last_progression()
last_status =
job.status
|> Jobs.get_last_status()
cond do
last_status == nil ->
count + 1
NaiveDateTime.compare(last_progression.updated_at, last_status.updated_at) == :gt ->
count + 1
NaiveDateTime.compare(last_progression.updated_at, last_status.updated_at) == :eq and
last_status.state == :processing ->
count + 1
true ->
count
end
end
end
defp count_for_status(job, count, :queued) do
last_status = Jobs.get_last_status(job.status)
last_progression = Progressions.get_last_progression(job.progressions)
case {last_status, last_progression} do
{nil, nil} ->
count + 1
{nil, _} ->
count
{last_status, nil} when last_status.state == :queued ->
count + 1
{last_status, nil} when last_status.state == :retrying ->
count + 1
{last_status, _} when last_status.state == :retrying ->
if NaiveDateTime.compare(last_progression.updated_at, last_status.updated_at) == :gt do
count
else
count + 1
end
{_last_status, _} ->
count
end
end
defp count_for_status(job, count, status) do
case Jobs.get_last_status(job.status) do
nil -> count
last_status when last_status.state == status -> count + 1
_last_status -> count
end
end
# If a job status is not taken into account in the matrix, the step is considered processing
defp is_still_processing(job_status) do
job_status.processing > 0 || job_status.queued > 0 ||
((job_status.skipped > 0 || job_status.completed > 0) &&
job_status.completed + job_status.skipped != job_status.total &&
job_status.stopped + job_status.paused == 0)
end
defp is_skipped(job_status) do
job_status.skipped > 0 && job_status.skipped == job_status.total
end
defp is_completed(job_status) do
job_status.completed > 0 && job_status.completed + job_status.skipped == job_status.total
end
end