Skip to content

Commit 3fe81d8

Browse files
close #4584 (#4585)
1 parent 2a78d3e commit 3fe81d8

3 files changed

Lines changed: 118 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ and this project adheres to
3939

4040
### Fixed
4141

42+
- Consider manual runs for "next cron run input" via the
43+
`last_run_final_dataclip` function
44+
[#4584](https://github.com/OpenFn/lightning/issues/4584)
4245
- Proper warn & error for exceeding max dataclip size
4346
[#4524](https://github.com/OpenFn/lightning/issues/4524)
4447
- Copying api tokens doesn't work on unsecure non-localhost contexts

lib/lightning/invocation.ex

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -229,14 +229,16 @@ defmodule Lightning.Invocation do
229229
end
230230

231231
@doc """
232-
Returns the final dataclip from the last successful run for a trigger.
233-
Used when cron_cursor_job_id is nil (use final run state).
232+
Returns the final dataclip from the last successful run for a trigger's
233+
workflow. Used when cron_cursor_job_id is nil (use final run state).
234+
235+
Scopes by workflow (not trigger) so that manual runs are also considered.
234236
"""
235-
def last_run_final_dataclip(%Trigger{id: trigger_id}) do
237+
def last_run_final_dataclip(%Trigger{workflow_id: workflow_id}) do
236238
from(r in Run,
237239
join: wo in assoc(r, :work_order),
238240
join: d in assoc(r, :final_dataclip),
239-
where: wo.trigger_id == ^trigger_id,
241+
where: wo.workflow_id == ^workflow_id,
240242
where: r.state == :success,
241243
where: is_nil(d.wiped_at),
242244
order_by: [desc: r.finished_at],

test/lightning/invocation_test.exs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,115 @@ defmodule Lightning.InvocationTest do
714714
assert result.id == final_dataclip.id
715715
end
716716

717+
test "returns the final dataclip from a manual run (no trigger on work order)" do
718+
project = insert(:project)
719+
720+
%{workflow: workflow, trigger: trigger, snapshot: snapshot} =
721+
build_workflow(project: project)
722+
723+
dataclip = insert(:dataclip, project: project)
724+
725+
final_dataclip =
726+
insert(:dataclip,
727+
project: project,
728+
body: %{"manual_final" => "state"},
729+
type: :step_result
730+
)
731+
732+
[job] = workflow.jobs
733+
734+
# Manual run: work order has no trigger, run has starting_job instead
735+
wo =
736+
insert(:workorder,
737+
workflow: workflow,
738+
trigger: nil,
739+
dataclip: dataclip,
740+
snapshot: snapshot
741+
)
742+
743+
insert(:run,
744+
work_order: wo,
745+
dataclip: dataclip,
746+
starting_job: job,
747+
snapshot: snapshot,
748+
state: :success,
749+
finished_at: DateTime.utc_now(),
750+
final_dataclip: final_dataclip
751+
)
752+
753+
result = Invocation.get_next_cron_run_dataclip(trigger)
754+
assert result.id == final_dataclip.id
755+
end
756+
757+
test "prefers the most recent successful run regardless of trigger" do
758+
project = insert(:project)
759+
760+
%{workflow: workflow, trigger: trigger, snapshot: snapshot} =
761+
build_workflow(project: project)
762+
763+
[job] = workflow.jobs
764+
765+
old_dataclip = insert(:dataclip, project: project)
766+
767+
old_final =
768+
insert(:dataclip,
769+
project: project,
770+
body: %{"old" => "state"},
771+
type: :step_result
772+
)
773+
774+
# Older cron-triggered run
775+
old_wo =
776+
insert(:workorder,
777+
workflow: workflow,
778+
trigger: trigger,
779+
dataclip: old_dataclip,
780+
snapshot: snapshot
781+
)
782+
783+
insert(:run,
784+
work_order: old_wo,
785+
dataclip: old_dataclip,
786+
starting_trigger: trigger,
787+
snapshot: snapshot,
788+
state: :success,
789+
finished_at: ~U[2025-01-01 00:00:00Z],
790+
final_dataclip: old_final
791+
)
792+
793+
# Newer manual run
794+
new_dataclip = insert(:dataclip, project: project)
795+
796+
new_final =
797+
insert(:dataclip,
798+
project: project,
799+
body: %{"new" => "state"},
800+
type: :step_result
801+
)
802+
803+
new_wo =
804+
insert(:workorder,
805+
workflow: workflow,
806+
trigger: nil,
807+
dataclip: new_dataclip,
808+
snapshot: snapshot
809+
)
810+
811+
insert(:run,
812+
work_order: new_wo,
813+
dataclip: new_dataclip,
814+
starting_job: job,
815+
snapshot: snapshot,
816+
state: :success,
817+
finished_at: ~U[2025-06-01 00:00:00Z],
818+
final_dataclip: new_final
819+
)
820+
821+
# Should use the newer manual run's final dataclip
822+
result = Invocation.get_next_cron_run_dataclip(trigger)
823+
assert result.id == new_final.id
824+
end
825+
717826
test "skips wiped dataclips and returns nil" do
718827
project = insert(:project)
719828

0 commit comments

Comments
 (0)