Class: Wrapbox::Runner::Ecs

Inherits:
Object
  • Object
show all
Defined in:
lib/wrapbox/runner/ecs.rb

Defined Under Namespace

Classes: Cli, ContainerAbnormalEnd, ExecutionFailure, ExecutionTimeout, LackResource, LaunchFailure, Parameter

Constant Summary collapse

EXECUTION_RETRY_INTERVAL =
3
WAIT_DELAY =
5
TERM_TIMEOUT =
120
HOST_TERMINATED_REASON_REGEXP =
/Host EC2.*terminated/

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ Ecs

Returns a new instance of Ecs.



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/wrapbox/runner/ecs.rb', line 49

def initialize(options)
  @name = options[:name]
  @revision = options[:revision]
  @cluster = options[:cluster]
  @region = options[:region]
  @volumes = options[:volumes]
  @placement_constraints = options[:placement_constraints]
  @placement_strategy = options[:placement_strategy]
  @launch_type = options[:launch_type]
  @requires_compatibilities = options[:requires_compatibilities]
  @network_mode = options[:network_mode]
  @network_configuration = options[:network_configuration]
  @cpu = options[:cpu]
  @memory = options[:memory]

  @container_definitions = options[:container_definition] ? [options[:container_definition]] : options[:container_definitions] || []
  @container_definitions.concat(options[:additional_container_definitions]) if options[:additional_container_definitions] # deprecated

  if !@container_definitions.empty? && options[:task_definition]
    raise "Please set only one of `container_definition` and `task_definition`"
  end

  if options[:additional_container_definitions] && !options[:additional_container_definitions].empty?
    warn "`additional_container_definitions` is deprecated parameter, Use `container_definitions` instead of it"
  end

  @task_definition_info = options[:task_definition]

  if !@container_definitions.empty?
    @task_definition_name = "wrapbox_#{@name}"
    @main_container_name = @container_definitions[0][:name] || @task_definition_name
  elsif @task_definition_info
    @task_definition_name = @task_definition_info[:task_definition_name]
    @main_container_name = @task_definition_info[:main_container_name]
    unless @main_container_name
      raise "Please set `task_definition[:main_container_name]`"
    end
  end

  @container_definitions.each do |d|
    d[:docker_labels]&.stringify_keys!
    d.dig(:log_configuration, :options)&.stringify_keys!
  end

  @task_role_arn = options[:task_role_arn]
  @execution_role_arn = options[:execution_role_arn]
  $stdout.sync = true
  @logger = Logger.new($stdout)
  if options[:log_fetcher]
    type = options[:log_fetcher].delete(:type)
    @log_fetcher = LogFetcher.new(type, options[:log_fetcher])
  end
end

Instance Attribute Details

#clusterObject (readonly)

Returns the value of attribute cluster.



29
30
31
# File 'lib/wrapbox/runner/ecs.rb', line 29

def cluster
  @cluster
end

#container_definitionsObject (readonly)

Returns the value of attribute container_definitions.



29
30
31
# File 'lib/wrapbox/runner/ecs.rb', line 29

def container_definitions
  @container_definitions
end

#cpuObject (readonly)

Returns the value of attribute cpu.



29
30
31
# File 'lib/wrapbox/runner/ecs.rb', line 29

def cpu
  @cpu
end

#execution_role_arnObject (readonly)

Returns the value of attribute execution_role_arn.



29
30
31
# File 'lib/wrapbox/runner/ecs.rb', line 29

def execution_role_arn
  @execution_role_arn
end

#launch_typeObject (readonly)

Returns the value of attribute launch_type.



29
30
31
# File 'lib/wrapbox/runner/ecs.rb', line 29

def launch_type
  @launch_type
end

#main_container_nameObject (readonly)

Returns the value of attribute main_container_name.



29
30
31
# File 'lib/wrapbox/runner/ecs.rb', line 29

def main_container_name
  @main_container_name
end

#memoryObject (readonly)

Returns the value of attribute memory.



29
30
31
# File 'lib/wrapbox/runner/ecs.rb', line 29

def memory
  @memory
end

#nameObject (readonly)

Returns the value of attribute name.



29
30
31
# File 'lib/wrapbox/runner/ecs.rb', line 29

def name
  @name
end

#network_configurationObject (readonly)

Returns the value of attribute network_configuration.



29
30
31
# File 'lib/wrapbox/runner/ecs.rb', line 29

def network_configuration
  @network_configuration
end

#network_modeObject (readonly)

Returns the value of attribute network_mode.



29
30
31
# File 'lib/wrapbox/runner/ecs.rb', line 29

def network_mode
  @network_mode
end

#placement_constraintsObject (readonly)

Returns the value of attribute placement_constraints.



29
30
31
# File 'lib/wrapbox/runner/ecs.rb', line 29

def placement_constraints
  @placement_constraints
end

#placement_strategyObject (readonly)

Returns the value of attribute placement_strategy.



29
30
31
# File 'lib/wrapbox/runner/ecs.rb', line 29

def placement_strategy
  @placement_strategy
end

#regionObject (readonly)

Returns the value of attribute region.



29
30
31
# File 'lib/wrapbox/runner/ecs.rb', line 29

def region
  @region
end

#requires_compatibilitiesObject (readonly)

Returns the value of attribute requires_compatibilities.



29
30
31
# File 'lib/wrapbox/runner/ecs.rb', line 29

def requires_compatibilities
  @requires_compatibilities
end

#revisionObject (readonly)

Returns the value of attribute revision.



29
30
31
# File 'lib/wrapbox/runner/ecs.rb', line 29

def revision
  @revision
end

#task_definition_nameObject (readonly)

Returns the value of attribute task_definition_name.



29
30
31
# File 'lib/wrapbox/runner/ecs.rb', line 29

def task_definition_name
  @task_definition_name
end

#task_role_arnObject (readonly)

Returns the value of attribute task_role_arn.



29
30
31
# File 'lib/wrapbox/runner/ecs.rb', line 29

def task_role_arn
  @task_role_arn
end

#volumesObject (readonly)

Returns the value of attribute volumes.



29
30
31
# File 'lib/wrapbox/runner/ecs.rb', line 29

def volumes
  @volumes
end

Instance Method Details

#run(class_name, method_name, args, container_definition_overrides: {}, **parameters) ⇒ Object



125
126
127
128
129
130
131
132
133
134
# File 'lib/wrapbox/runner/ecs.rb', line 125

def run(class_name, method_name, args, container_definition_overrides: {}, **parameters)
  task_definition = prepare_task_definition(container_definition_overrides)
  parameter = Parameter.new(**parameters)

  run_task(
    task_definition.task_definition_arn, class_name, method_name, args,
    ["bundle", "exec", "rake", "wrapbox:run"],
    parameter
  )
end

#run_cmd(cmds, container_definition_overrides: {}, ignore_signal: false, **parameters) ⇒ Object



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/wrapbox/runner/ecs.rb', line 136

def run_cmd(cmds, container_definition_overrides: {}, ignore_signal: false, **parameters)
  ths = []

  task_definition = prepare_task_definition(container_definition_overrides)

  cmds << nil if cmds.empty?
  cmds.each_with_index do |cmd, idx|
    ths << Thread.new(cmd, idx) do |c, i|
      Thread.current[:cmd_index] = i
      envs = (parameters[:environments] || []) + [{name: "WRAPBOX_CMD_INDEX", value: i.to_s}]
      run_task(
        task_definition.task_definition_arn, nil, nil, nil,
        c&.shellsplit,
        Parameter.new(**parameters.merge(environments: envs))
      )
    end
  end
  ths.each(&:join)

  true
rescue SignalException => e
  sig = "SIG#{Signal.signame(e.signo)}"
  if ignore_signal
    @logger.info("Receive #{sig} signal. But ECS Tasks continue running")
  else
    @logger.info("Receive #{sig} signal. Stop All tasks")
    ths.each do |th|
      th.report_on_exception = false
      th.raise(e)
    end
    wait_until = Time.now + TERM_TIMEOUT + 15 # thread_timeout_buffer
    ths.each do |th|
      wait = wait_until - Time.now
      th.join(wait) if wait.positive?
    end
  end
  nil
end