Skip to content

Commit aed4690

Browse files
committed
chore: demo app updates, dev config & umbrella lockfile
Phoenix demo dev config, the example drip-email-campaign workflow, home LiveView, the durable upgrade migration, and the root mix.lock.
1 parent c60e8c1 commit aed4690

5 files changed

Lines changed: 73 additions & 27 deletions

File tree

examples/phoenix_demo/config/dev.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ config :phoenix_demo, dev_routes: true
7979
# automatically with `mix phx.server`. To opt out (e.g. on a machine
8080
# without Node/pnpm), set this to `false` — the LV layout will then
8181
# serve the pre-built bundle in `priv/static/durable_dashboard/`.
82-
config :durable_dashboard, dev_mode: true
82+
config :durable_dashboard, dev_mode: false
8383

8484
# Do not include metadata nor timestamps in development logs
8585
config :logger, :default_formatter, format: "[$level] $message\n"

examples/phoenix_demo/lib/phoenix_demo/workflows/drip_email_campaign_workflow.ex

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
defmodule PhoenixDemo.Workflows.DripEmailCampaignWorkflow do
22
@moduledoc """
3-
Multi-stage email drip campaign that visibly progresses across waits.
4-
Day 2 is sent after a `schedule_at(now + drip_scale s)` pause; day 7 is
5-
sent after a `sleep(drip_scale s)` pause.
3+
Three-stage email drip that visibly cycles `:running → :waiting → :running`
4+
across progressively longer gaps:
65
7-
Both delays default to 30 seconds so a demo session can complete in under
8-
two minutes. Override with `config :phoenix_demo, :drip_scale, 5`.
6+
welcome
7+
→ schedule_at(now + 30s) → followup #1
8+
→ sleep(1m) → followup #2
9+
→ sleep(2m) → followup #3
10+
→ complete
911
10-
Showcases: `sleep`, `schedule_at`, multi-stage workflows that go through
11-
`:waiting → :running:waiting` cycles.
12+
Showcases: `schedule_at`, `sleep`, and a multi-stage workflow whose status
13+
flips between `:running` and `:waiting` three times.
1214
1315
Input: `%{"customer_email" => "alice@example.com", "campaign" => "welcome"}`
1416
"""
@@ -20,8 +22,6 @@ defmodule PhoenixDemo.Workflows.DripEmailCampaignWorkflow do
2022

2123
require Logger
2224

23-
@drip_scale Application.compile_env(:phoenix_demo, :drip_scale, 30)
24-
2525
workflow "drip_email_campaign", timeout: minutes(30) do
2626
step :send_welcome, fn data ->
2727
email = data["customer_email"] || "demo@example.com"
@@ -35,31 +35,44 @@ defmodule PhoenixDemo.Workflows.DripEmailCampaignWorkflow do
3535
{:ok, assign(data, "email_step", "welcome_sent")}
3636
end
3737

38-
step :wait_day_2, fn data ->
39-
until = DateTime.add(DateTime.utc_now(), @drip_scale, :second)
40-
Logger.info("[Drip] Scheduling day-2 nudge at #{DateTime.to_iso8601(until)}")
38+
step :wait_first, fn data ->
39+
until = DateTime.add(DateTime.utc_now(), 30, :second)
40+
Logger.info("[Drip] Scheduling followup #1 at #{DateTime.to_iso8601(until)}")
4141
schedule_at(until)
4242
{:ok, data}
4343
end
4444

45-
step :send_day_2_email, fn data ->
45+
step :send_first_followup, fn data ->
46+
email = get_context(:customer_email)
47+
Logger.info("[Drip] Followup #1 → #{email}")
48+
put_context(:first_sent_at, DateTime.utc_now() |> DateTime.to_iso8601())
49+
{:ok, assign(data, "email_step", "first_sent")}
50+
end
51+
52+
step :wait_second, fn data ->
53+
Logger.info("[Drip] Sleeping 1m before followup #2")
54+
sleep(minutes(1))
55+
{:ok, data}
56+
end
57+
58+
step :send_second_followup, fn data ->
4659
email = get_context(:customer_email)
47-
Logger.info("[Drip] Day-2 email#{email}")
48-
put_context(:day_2_sent_at, DateTime.utc_now() |> DateTime.to_iso8601())
49-
{:ok, assign(data, "email_step", "day_2_sent")}
60+
Logger.info("[Drip] Followup #2#{email}")
61+
put_context(:second_sent_at, DateTime.utc_now() |> DateTime.to_iso8601())
62+
{:ok, assign(data, "email_step", "second_sent")}
5063
end
5164

52-
step :wait_day_7, fn data ->
53-
Logger.info("[Drip] Sleeping #{@drip_scale}s before day-7 email")
54-
sleep(seconds(@drip_scale))
65+
step :wait_third, fn data ->
66+
Logger.info("[Drip] Sleeping 2m before followup #3")
67+
sleep(minutes(2))
5568
{:ok, data}
5669
end
5770

58-
step :send_day_7_email, fn data ->
71+
step :send_third_followup, fn data ->
5972
email = get_context(:customer_email)
60-
Logger.info("[Drip] Day-7 email#{email}")
61-
put_context(:day_7_sent_at, DateTime.utc_now() |> DateTime.to_iso8601())
62-
{:ok, assign(data, "email_step", "day_7_sent")}
73+
Logger.info("[Drip] Followup #3#{email}")
74+
put_context(:third_sent_at, DateTime.utc_now() |> DateTime.to_iso8601())
75+
{:ok, assign(data, "email_step", "third_sent")}
6376
end
6477

6578
step :complete_campaign, fn _data ->
@@ -71,8 +84,9 @@ defmodule PhoenixDemo.Workflows.DripEmailCampaignWorkflow do
7184
"campaign" => get_context(:campaign),
7285
"status" => "completed",
7386
"welcome_sent_at" => get_context(:welcome_sent_at),
74-
"day_2_sent_at" => get_context(:day_2_sent_at),
75-
"day_7_sent_at" => get_context(:day_7_sent_at)
87+
"first_sent_at" => get_context(:first_sent_at),
88+
"second_sent_at" => get_context(:second_sent_at),
89+
"third_sent_at" => get_context(:third_sent_at)
7690
}}
7791
end
7892
end

examples/phoenix_demo/lib/phoenix_demo_web/live/home_live.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ defmodule PhoenixDemoWeb.HomeLive do
9191
title: "Drip Email Campaign",
9292
module: Workflows.DripEmailCampaignWorkflow,
9393
description:
94-
"Welcome → schedule_at(+30s) → day-2 → sleep(30s) → day-7. The status flips :running ↔ :waiting visibly across the run.",
94+
"Welcome → schedule_at(+30s) → followup #1 → sleep(1m) → followup #2 → sleep(2m) → followup #3. Status flips :running ↔ :waiting three times.",
9595
pills: ["sleep", "schedule_at", "multi-stage"],
9696
fields: [
9797
%{
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
defmodule PhoenixDemo.Repo.Migrations.UpgradeDurableToV20260623000001 do
2+
use Ecto.Migration
3+
4+
def up do
5+
Durable.Migration.up(to: 20260623000001, prefix: "durable")
6+
end
7+
8+
def down do
9+
Durable.Migration.down(to: 20260623000000, prefix: "durable")
10+
end
11+
end

mix.lock

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
%{
2+
"crontab": {:hex, :crontab, "1.2.0", "503611820257939d5d0fd272eb2b454f48a470435a809479ddc2c40bb515495c", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "ebd7ef4d831e1b20fa4700f0de0284a04cac4347e813337978e25b4cc5cc2207"},
3+
"db_connection": {:hex, :db_connection, "2.10.0", "8ff756471e41765bd5563b633f73e9a94bbc138816e8644bb17d0d91bf260a95", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "02cdd01b45efb1b550e68edbbea41be32de9b24bb07e1ea0e9cbc522ac377e54"},
4+
"decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"},
5+
"ecto": {:hex, :ecto, "3.13.5", "9d4a69700183f33bf97208294768e561f5c7f1ecf417e0fa1006e4a91713a834", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "df9efebf70cf94142739ba357499661ef5dbb559ef902b68ea1f3c1fabce36de"},
6+
"ecto_sql": {:hex, :ecto_sql, "3.13.5", "2f8282b2ad97bf0f0d3217ea0a6fff320ead9e2f8770f810141189d182dc304e", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.13.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "aa36751f4e6a2b56ae79efb0e088042e010ff4935fc8684e74c23b1f49e25fdc"},
7+
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
8+
"mime": {:hex, :mime, "2.0.7", "b8d739037be7cd402aee1ba0306edfdef982687ee7e9859bee6198c1e7e2f128", [:mix], [], "hexpm", "6171188e399ee16023ffc5b76ce445eb6d9672e2e241d2df6050f3c771e80ccd"},
9+
"nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"},
10+
"phoenix": {:hex, :phoenix, "1.8.5", "919db335247e6d4891764dc3063415b0d2457641c5f9b3751b5df03d8e20bbcf", [:mix], [{:bandit, "~> 1.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "83b2bb125127e02e9f475c8e3e92736325b5b01b0b9b05407bcb4083b7a32485"},
11+
"phoenix_html": {:hex, :phoenix_html, "4.3.0", "d3577a5df4b6954cd7890c84d955c470b5310bb49647f0a114a6eeecc850f7ad", [:mix], [], "hexpm", "3eaa290a78bab0f075f791a46a981bbe769d94bc776869f4f3063a14f30497ad"},
12+
"phoenix_live_view": {:hex, :phoenix_live_view, "1.1.28", "8a8e123d018025f756605a2fb02a4854f0d3cd7b207f710fef1fd5d9d72d0254", [:mix], [{:igniter, ">= 0.6.16 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:lazy_html, "~> 0.1.0", [hex: :lazy_html, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0 or ~> 1.8.0-rc", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "24faad535b65089642c3a7d84088109dc58f49c1f1c5a978659855d643466353"},
13+
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.2.0", "ff3a5616e1bed6804de7773b92cbccfc0b0f473faf1f63d7daf1206c7aeaaa6f", [:mix], [], "hexpm", "adc313a5bf7136039f63cfd9668fde73bba0765e0614cba80c06ac9460ff3e96"},
14+
"phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"},
15+
"plug": {:hex, :plug, "1.19.1", "09bac17ae7a001a68ae393658aa23c7e38782be5c5c00c80be82901262c394c0", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "560a0017a8f6d5d30146916862aaf9300b7280063651dd7e532b8be168511e62"},
16+
"plug_crypto": {:hex, :plug_crypto, "2.1.1", "19bda8184399cb24afa10be734f84a16ea0a2bc65054e23a62bb10f06bc89491", [:mix], [], "hexpm", "6470bce6ffe41c8bd497612ffde1a7e4af67f36a15eea5f921af71cf3e11247c"},
17+
"postgrex": {:hex, :postgrex, "0.22.0", "fb027b58b6eab1f6de5396a2abcdaaeb168f9ed4eccbb594e6ac393b02078cbd", [:mix], [{:db_connection, "~> 2.9", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "a68c4261e299597909e03e6f8ff5a13876f5caadaddd0d23af0d0a61afcc5d84"},
18+
"telemetry": {:hex, :telemetry, "1.4.1", "ab6de178e2b29b58e8256b92b382ea3f590a47152ca3651ea857a6cae05ac423", [:rebar3], [], "hexpm", "2172e05a27531d3d31dd9782841065c50dd5c3c7699d95266b2edd54c2dafa1c"},
19+
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
20+
"websock_adapter": {:hex, :websock_adapter, "0.5.9", "43dc3ba6d89ef5dec5b1d0a39698436a1e856d000d84bf31a3149862b01a287f", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "5534d5c9adad3c18a0f58a9371220d75a803bf0b9a3d87e6fe072faaeed76a08"},
21+
}

0 commit comments

Comments
 (0)