1
1
class Kamal ::Cli ::App ::Boot
2
- attr_reader :host , :role , :version , :sshkit
3
- delegate :execute , :capture_with_info , :info , to : :sshkit
4
- delegate :uses_cord? , :assets? , to : :role
2
+ attr_reader :host , :role , :version , :barrier , : sshkit
3
+ delegate :execute , :capture_with_info , :capture_with_pretty_json , : info, :error , to : :sshkit
4
+ delegate :uses_cord? , :assets? , :running_traefik? , to : :role
5
5
6
- def initialize ( host , role , version , sshkit )
6
+ def initialize ( host , role , sshkit , version , barrier )
7
7
@host = host
8
8
@role = role
9
9
@version = version
10
+ @barrier = barrier
10
11
@sshkit = sshkit
11
12
end
12
13
13
14
def run
14
15
old_version = old_version_renamed_if_clashing
15
16
16
- start_new_version
17
+ wait_at_barrier if queuer?
18
+
19
+ begin
20
+ start_new_version
21
+ rescue => e
22
+ close_barrier if gatekeeper?
23
+ stop_new_version
24
+ raise
25
+ end
26
+
27
+ release_barrier if gatekeeper?
17
28
18
29
if old_version
19
30
stop_old_version ( old_version )
20
31
end
21
32
end
22
33
23
34
private
24
- def app
25
- @app ||= KAMAL . app ( role : role , host : host )
26
- end
27
-
28
- def auditor
29
- @auditor = KAMAL . auditor ( role : role )
30
- end
31
-
32
- def audit ( message )
33
- execute *auditor . record ( message ) , verbosity : :debug
34
- end
35
-
36
35
def old_version_renamed_if_clashing
37
36
if capture_with_info ( *app . container_id_for_version ( version ) , raise_on_non_zero_exit : false ) . present?
38
37
renamed_version = "#{ version } _replaced_#{ SecureRandom . hex ( 8 ) } "
@@ -46,12 +45,17 @@ def old_version_renamed_if_clashing
46
45
47
46
def start_new_version
48
47
audit "Booted app version #{ version } "
48
+
49
49
execute *app . tie_cord ( role . cord_host_file ) if uses_cord?
50
50
hostname = "#{ host . to_s [ 0 ...51 ] . gsub ( /\. +$/ , '' ) } -#{ SecureRandom . hex ( 6 ) } "
51
51
execute *app . run ( hostname : hostname )
52
52
Kamal ::Cli ::Healthcheck ::Poller . wait_for_healthy ( pause_after_ready : true ) { capture_with_info ( *app . status ( version : version ) ) }
53
53
end
54
54
55
+ def stop_new_version
56
+ execute *app . stop ( version : version ) , raise_on_non_zero_exit : false
57
+ end
58
+
55
59
def stop_old_version ( version )
56
60
if uses_cord?
57
61
cord = capture_with_info ( *app . cord ( version : version ) , raise_on_non_zero_exit : false ) . strip
@@ -65,4 +69,51 @@ def stop_old_version(version)
65
69
66
70
execute *app . clean_up_assets if assets?
67
71
end
72
+
73
+ def release_barrier
74
+ if barrier . open
75
+ info "First #{ KAMAL . primary_role } container is healthy on #{ host } , booting other roles"
76
+ end
77
+ end
78
+
79
+ def wait_at_barrier
80
+ info "Waiting for the first healthy #{ KAMAL . primary_role } container before booting #{ role } on #{ host } ..."
81
+ barrier . wait
82
+ info "First #{ KAMAL . primary_role } container is healthy, booting #{ role } on #{ host } ..."
83
+ rescue Kamal ::Cli ::Healthcheck ::Error
84
+ info "First #{ KAMAL . primary_role } container is unhealthy, not booting #{ role } on #{ host } "
85
+ raise
86
+ end
87
+
88
+ def close_barrier
89
+ if barrier . close
90
+ info "First #{ KAMAL . primary_role } container is unhealthy on #{ host } , not booting other roles"
91
+ error capture_with_info ( *app . logs ( version : version ) )
92
+ error capture_with_info ( *app . container_health_log ( version : version ) )
93
+ end
94
+ end
95
+
96
+ def barrier_role?
97
+ role == KAMAL . primary_role
98
+ end
99
+
100
+ def app
101
+ @app ||= KAMAL . app ( role : role , host : host )
102
+ end
103
+
104
+ def auditor
105
+ @auditor = KAMAL . auditor ( role : role )
106
+ end
107
+
108
+ def audit ( message )
109
+ execute *auditor . record ( message ) , verbosity : :debug
110
+ end
111
+
112
+ def gatekeeper?
113
+ barrier && barrier_role?
114
+ end
115
+
116
+ def queuer?
117
+ barrier && !barrier_role?
118
+ end
68
119
end
0 commit comments