@@ -4,16 +4,25 @@ defmodule Meadow.Application do
44 @ moduledoc false
55
66 use Application
7+ use Retry
78 alias Meadow.Application.Children
89 alias Meadow.Config.Runtime
910
1011 require Logger
12+ require WaitForIt
1113
1214 def start ( _type , _args ) do
1315 result =
1416 Supervisor . start_link (
1517 [
16- { DynamicSupervisor , max_restarts: 4096 , strategy: :one_for_one , name: Meadow.Supervisor }
18+ { DynamicSupervisor ,
19+ max_restarts: 4096 , strategy: :one_for_one , name: Meadow.Supervisor } ,
20+ { Horde.Registry , name: Meadow.HordeRegistry , keys: :unique , members: :auto } ,
21+ { Horde.DynamicSupervisor ,
22+ name: Meadow.HordeSupervisor ,
23+ distribution_strategy: Horde.UniformQuorumDistribution ,
24+ strategy: :one_for_one ,
25+ members: :auto }
1726 ] ,
1827 max_restarts: 4096 ,
1928 strategy: :one_for_one ,
@@ -26,22 +35,48 @@ defmodule Meadow.Application do
2635 Runtime . configure! ( )
2736 end
2837
38+ if System . get_env ( "CLUSTER_ENABLED" ) == "true" do
39+ Logger . info ( "Starting libcluster" )
40+ topologies = Application . get_env ( :libcluster , :topologies , [ ] )
41+
42+ DynamicSupervisor . start_child (
43+ Meadow.Supervisor ,
44+ { Cluster.Supervisor , [ topologies , [ name: Meadow.ClusterSupervisor ] ] }
45+ )
46+
47+ Logger . info ( "Waiting for cluster" )
48+
49+ WaitForIt . case_wait Horde.Cluster . members ( Meadow.HordeSupervisor ) ,
50+ timeout: :timer . seconds ( 10 ) ,
51+ interval: :timer . seconds ( 1 ) do
52+ nodes when length ( nodes ) > 1 ->
53+ Logger . info ( "Cluster formed with nodes: #{ inspect ( nodes ) } " )
54+ else
55+ Logger . warning ( "Timeout waiting for cluster formation. Continuing with single node." )
56+ end
57+
58+ Logger . info ( "Waiting for quorum" )
59+ Horde.DynamicSupervisor . wait_for_quorum ( Meadow.HordeSupervisor , :timer . seconds ( 10 ) )
60+ end
61+
62+ Logger . info ( "Starting Anubis MCP server" )
63+ Application . ensure_all_started ( :anubis_mcp )
64+
2965 unless System . get_env ( "MEADOW_NO_REPO" ) do
3066 DynamicSupervisor . start_child ( Meadow.Supervisor , Meadow.Repo )
3167 DynamicSupervisor . start_child ( Meadow.Supervisor , Meadow.Repo.Indexing )
3268 Meadow.Repo . wait_for_connection ( )
3369 end
3470
35- base_children = [
71+ [
3672 { Phoenix.PubSub , [ name: Meadow.PubSub , adapter: Phoenix.PubSub.PG2 ] } ,
3773 Meadow.Telemetry ,
3874 { Registry , keys: :unique , name: Meadow.TaskRegistry }
3975 ]
76+ |> start_children ( )
4077
41- children = base_children ++ Children . specs ( )
42-
43- children
44- |> Enum . each ( & DynamicSupervisor . start_child ( Meadow.Supervisor , & 1 ) )
78+ Children . specs ( )
79+ |> start_children ( )
4580
4681 :telemetry . attach (
4782 "reorder-file-sets-stop-handler" ,
@@ -53,10 +88,49 @@ defmodule Meadow.Application do
5388 result
5489 end
5590
91+ def start_children ( children ) do
92+ retry with: exponential_backoff ( ) |> randomize ( ) |> cap ( 10_000 ) |> Stream . take ( 10 ) do
93+ children
94+ |> Enum . each ( fn spec ->
95+ if distributed? ( spec ) do
96+ Horde.DynamicSupervisor . start_child ( Meadow.HordeSupervisor , spec )
97+ else
98+ DynamicSupervisor . start_child ( Meadow.Supervisor , spec )
99+ end
100+ |> case do
101+ { :ok , _pid } ->
102+ :ok
103+
104+ { :error , { :already_started , _pid } } ->
105+ Logger . warning ( "Not starting #{ inspect ( spec ) } : already started" )
106+ :ok
107+
108+ { :error , reason } ->
109+ Logger . error ( "Failed to start child #{ inspect ( spec ) } : #{ inspect ( reason ) } " )
110+ end
111+ end )
112+ end
113+ end
114+
56115 # Tell Phoenix to update the endpoint configuration
57116 # whenever the application is updated.
58117 def config_change ( changed , _new , removed ) do
59118 MeadowWeb.Endpoint . config_change ( changed , removed )
60119 :ok
61120 end
121+
122+ defp spec_name ( child_spec ) do
123+ case child_spec do
124+ % { start: { _mod , _fun , [ args ] } } when is_list ( args ) -> Keyword . get ( args , :name )
125+ % { start: { _mod , _fun , args } } when is_list ( args ) -> Keyword . get ( args , :name )
126+ { _mod , opts } when is_list ( opts ) -> Keyword . get ( opts , :name )
127+ % { id: { :via , Horde.Registry , _ } = name } -> name
128+ _ -> nil
129+ end
130+ end
131+
132+ defp distributed? ( child_spec ) , do: spec_name ( child_spec ) |> via_horde? ( )
133+
134+ defp via_horde? ( { :via , Horde.Registry , _ } ) , do: true
135+ defp via_horde? ( _ ) , do: false
62136end
0 commit comments