@@ -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.UniformDistribution ,
24+ strategy: :one_for_one ,
25+ members: :auto }
1726 ] ,
1827 max_restarts: 4096 ,
1928 strategy: :one_for_one ,
@@ -26,22 +35,40 @@ 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 = [
36- { Phoenix.PubSub , [ name: Meadow.PubSub , adapter: Phoenix.PubSub.PG2 ] } ,
37- Meadow.Telemetry ,
38- { Registry , keys: :unique , name: Meadow.TaskRegistry }
39- ]
40-
41- children = base_children ++ Children . specs ( )
42-
43- children
44- |> Enum . each ( & DynamicSupervisor . start_child ( Meadow.Supervisor , & 1 ) )
71+ start_children ( )
4572
4673 :telemetry . attach (
4774 "reorder-file-sets-stop-handler" ,
@@ -53,10 +80,68 @@ defmodule Meadow.Application do
5380 result
5481 end
5582
83+ def children do
84+ [
85+ { Phoenix.PubSub , [ name: Meadow.PubSub , adapter: Phoenix.PubSub.PG2 ] } ,
86+ Meadow.Telemetry ,
87+ { Registry , keys: :unique , name: Meadow.TaskRegistry }
88+ ] ++ Children . specs ( )
89+ end
90+
91+ def start_children ( ) do
92+ children ( )
93+ |> start_children ( )
94+ end
95+
96+ def start_children ( children ) do
97+ retry with: exponential_backoff ( ) |> randomize ( ) |> cap ( 10_000 ) |> Stream . take ( 10 ) do
98+ children
99+ |> Enum . each ( fn spec ->
100+ if distributed? ( spec ) do
101+ Horde.DynamicSupervisor . start_child ( Meadow.HordeSupervisor , spec )
102+ else
103+ DynamicSupervisor . start_child ( Meadow.Supervisor , spec )
104+ end
105+ |> case do
106+ { :ok , _pid } ->
107+ :ok
108+
109+ { :error , { :already_started , _pid } } ->
110+ Logger . warning ( "Not starting #{ inspect ( spec ) } : already started" )
111+ :ok
112+
113+ { :error , reason } ->
114+ Logger . error ( "Failed to start child #{ inspect ( spec ) } : #{ inspect ( reason ) } " )
115+ end
116+ end )
117+ end
118+ end
119+
120+ def start_distributed do
121+ children ( )
122+ |> Enum . filter ( & distributed? / 1 )
123+ |> start_children ( )
124+ end
125+
56126 # Tell Phoenix to update the endpoint configuration
57127 # whenever the application is updated.
58128 def config_change ( changed , _new , removed ) do
59129 MeadowWeb.Endpoint . config_change ( changed , removed )
60130 :ok
61131 end
132+
133+ defp spec_name ( child_spec ) do
134+ case child_spec do
135+ % { start: { _mod , _fun , [ args ] } } when is_list ( args ) -> Keyword . get ( args , :name )
136+ % { start: { _mod , _fun , args } } when is_list ( args ) -> Keyword . get ( args , :name )
137+ { _mod , opts } when is_list ( opts ) -> Keyword . get ( opts , :name )
138+ % { id: { :via , Horde.Registry , _ } = name } -> name
139+ _ -> nil
140+ end
141+ end
142+
143+ defp distributed? ( child_spec ) , do: spec_name ( child_spec ) |> via_horde? ( )
144+
145+ defp via_horde? ( { :via , Horde.Registry , _ } ) , do: true
146+ defp via_horde? ( _ ) , do: false
62147end
0 commit comments