aws-flow 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,5 +11,5 @@ Gem::Specification.new do |s|
11
11
  s.files = `git ls-files`.split("\n").reject {|file| file =~ /aws-flow-core/}
12
12
  s.require_paths << "lib/aws/"
13
13
  s.add_dependency "aws-sdk", "~> 1"
14
- s.add_dependency "aws-flow-core", "~> 1"
14
+ s.add_dependency "aws-flow-core", ">= 1.0.1"
15
15
  end
@@ -295,7 +295,7 @@ module AWS
295
295
  end
296
296
 
297
297
  # Represents an activity client.
298
- class ActivityClient < Module
298
+ class ActivityClient
299
299
  # Gets the data converter for the Activity Client.
300
300
  def data_converter
301
301
  @generic_client.data_converter
@@ -61,7 +61,7 @@ module AWS
61
61
  end
62
62
 
63
63
  def execute(&block)
64
- @log.error "Here are the pids that are currently running #{@pids}"
64
+ @log.info "Here are the pids that are currently running #{@pids}"
65
65
  raise RejectedExecutionException if @is_shutdown
66
66
  block_on_max_workers
67
67
  @log.debug "PARENT BEFORE FORK #{Process.pid}"
@@ -106,6 +106,17 @@ module AWS
106
106
  end
107
107
  end
108
108
 
109
+ def block_on_max_workers
110
+ @log.debug "block_on_max_workers workers=#{@pids.size}, max_workers=#{@max_workers}"
111
+ if @pids.size >= @max_workers
112
+ @log.info "Reached maximum number of workers (#{@max_workers}), \
113
+ waiting for some to finish"
114
+ begin
115
+ remove_completed_pids(true)
116
+ end while @pids.size >= @max_workers
117
+ end
118
+ end
119
+
109
120
  private
110
121
 
111
122
  # Remove all child processes from @pids list that have finished
@@ -132,17 +143,8 @@ module AWS
132
143
  end
133
144
  end
134
145
 
135
- def block_on_max_workers
136
- @log.debug "block_on_max_workers workers=#{@pids.size}, max_workers=#{@max_workers}"
137
- start_time = Time.now
138
- if @pids.size > @max_workers
139
- @log.info "Reached maximum number of workers (#{@max_workers}), \
140
- waiting for some to finish before polling again"
141
- begin
142
- remove_completed_pids(true)
143
- end while @pids.size > @max_workers
144
- end
145
- end
146
+
147
+
146
148
  end
147
149
 
148
150
  end
@@ -165,6 +165,9 @@ module AWS
165
165
  semaphore_needs_release = true
166
166
  @logger.debug "before the poll\n\n"
167
167
  begin
168
+ if use_forking
169
+ @executor.block_on_max_workers
170
+ end
168
171
  task = @domain.activity_tasks.poll_for_single_task(@task_list)
169
172
  @logger.error "got a task, #{task.activity_type.name}"
170
173
  @logger.error "The task token I got was: #{task.task_token}"
@@ -33,10 +33,10 @@ module AWS
33
33
 
34
34
  # @!visibility private
35
35
  def self.drill_on_future(future)
36
- while future.get.is_a? Future
36
+ while (future.respond_to? :is_flow_future?) && future.is_flow_future?
37
37
  future = future.get
38
38
  end
39
- future.get
39
+ future
40
40
  end
41
41
 
42
42
 
@@ -88,6 +88,12 @@ module AWS
88
88
  @return_value = Future.new
89
89
  end
90
90
 
91
+ # determines whether the object is a flow future. The contract is that
92
+ # flow futures must have a #get method.
93
+ def is_flow_future?
94
+ true
95
+ end
96
+
91
97
  def metadata
92
98
  @_metadata
93
99
  end
@@ -16,7 +16,7 @@
16
16
  module AWS
17
17
  module Flow
18
18
  def self.version
19
- "1.0.2"
19
+ "1.0.3"
20
20
  end
21
21
  end
22
22
  end
@@ -111,7 +111,6 @@ module AWS
111
111
  #
112
112
  def initialize(service, domain, task_list, *args)
113
113
  @workflow_definition_map = {}
114
- @executor = ForkingExecutor.new(:max_workers => 2, :log_level => 5)
115
114
  @workflow_type_options = []
116
115
  super(service, domain, task_list, *args)
117
116
  end
@@ -229,7 +228,6 @@ module AWS
229
228
  #
230
229
  def initialize(service, domain, task_list, *args, &block)
231
230
  @activity_definition_map = {}
232
- @executor = ForkingExecutor.new(:max_workers => 1)
233
231
  @activity_type_options = []
234
232
  @options = Utilities::interpret_block_for_options(WorkerOptions, block)
235
233
  super(service, domain, task_list, *args)
@@ -39,6 +39,12 @@ module AWS
39
39
  @return_value = Future.new
40
40
  end
41
41
 
42
+ # determines whether the object is a flow future. The contract is that
43
+ # flow futures must have a #get method.
44
+ def is_flow_future?
45
+ true
46
+ end
47
+
42
48
  def method_missing(method_name, *args, &block)
43
49
  @return_value.send(method_name, *args, &block)
44
50
  end
@@ -277,7 +277,6 @@ describe ForkingExecutor do
277
277
  sleep 3
278
278
  File.exists?(test_file_name).should == true
279
279
  ensure
280
-
281
280
  File.unlink(test_file_name)
282
281
  end
283
282
  end
@@ -849,6 +848,7 @@ describe "FakeHistory" do
849
848
  "StartTimer"
850
849
  BadWorkflow.trace.should == [:start]
851
850
  end
851
+
852
852
  it "makes sure that multiple schedules followed by a timeout work" do
853
853
  class SynchronousWorkflowTaskPoller < WorkflowTaskPoller
854
854
  def get_decision_tasks
@@ -1170,6 +1170,36 @@ describe "Misc tests" do
1170
1170
  end
1171
1171
  TestDecider.methods.map(&:to_sym).should include :signal
1172
1172
  end
1173
+
1174
+ it "ensures you can eager_autoload" do
1175
+ require 'aws'
1176
+ require 'aws/decider'
1177
+ AWS.eager_autoload!
1178
+ end
1179
+
1180
+ it "ensures that one worker for forking executor will only allow one thing to be processed at a time" do
1181
+ executor = ForkingExecutor.new(:max_workers => 1)
1182
+
1183
+ test_file_name = "ForkingExecutorRunOne"
1184
+ File.new(test_file_name, "w")
1185
+ start_time = Time.now
1186
+ executor.execute do
1187
+ File.open(test_file_name, "a+") { |f| f.write("First Execution\n")}
1188
+ sleep 4
1189
+ end
1190
+ # Because execute will block if the worker queue is full, we will wait here
1191
+ # if we have reached the max number of workers
1192
+ executor.execute { 2 + 2 }
1193
+ finish_time = Time.now
1194
+ # If we waited for the first task to finish, then we will have waited at
1195
+ # least 4 seconds; if we didn't, we should not have waited. Thus, if we have
1196
+ # waited > 3 seconds, we have likely waited for the first task to finish
1197
+ # before doing the second one
1198
+ (finish_time - start_time).should > 3
1199
+ File.unlink(test_file_name)
1200
+ end
1201
+
1202
+
1173
1203
  end
1174
1204
 
1175
1205
  describe FlowConstants do
@@ -1198,6 +1228,7 @@ end
1198
1228
 
1199
1229
 
1200
1230
 
1231
+
1201
1232
  describe "testing changing default values in RetryOptions and RetryPolicy" do
1202
1233
 
1203
1234
  it "will test exponential retry with a new retry function" do
@@ -1227,7 +1258,7 @@ describe "testing changing default values in RetryOptions and RetryPolicy" do
1227
1258
 
1228
1259
  it "will test whether we get the same jitter for a particular execution id" do
1229
1260
 
1230
- (FlowConstants.jitter_function.call(1, 100)).should equal(FlowConstants.jitter_function.call(1, 100))
1261
+ (FlowConstants.jitter_function.call(1, 100)).should equal(FlowConstants.jitter_function.call(1, 100))
1231
1262
 
1232
1263
  end
1233
1264
 
@@ -372,7 +372,6 @@ describe "RubyFlowDecider" do
372
372
 
373
373
  @forking_executor.shutdown(1)
374
374
  workflow_history = workflow_execution.events.map(&:event_type)
375
- workflow_execution.events.each {|x| p x}
376
375
  workflow_history.count("WorkflowExecutionCompleted").should == 1
377
376
  workflow_history.count("ActivityTaskCompleted").should == 4
378
377
  end
@@ -537,114 +536,116 @@ describe "RubyFlowDecider" do
537
536
  end
538
537
  describe "Handle_ tests" do
539
538
  # This also effectively tests "RequestCancelExternalWorkflowExecutionInitiated"
540
- it "ensures that handle_child_workflow_execution_canceled is correct" do
541
- class OtherCancellationChildWorkflow
542
- extend Workflows
543
- workflow(:entry_point) { {:version => 1, :task_list => "new_child_workflow", :execution_start_to_close_timeout => 3600} }
544
- def entry_point(arg)
545
- create_timer(5)
546
- end
547
- end
548
- class BadCancellationChildWorkflow
549
- extend Workflows
550
- workflow(:entry_point) { {:version => 1, :task_list => "new_parent_workflow", :execution_start_to_close_timeout => 3600} }
551
- def other_entry_point
552
- end
553
539
 
554
- def entry_point(arg)
555
- client = workflow_client($swf.client, $domain) { {:from_class => "OtherCancellationChildWorkflow"} }
556
- workflow_future = client.send_async(:start_execution, 5)
557
- client.request_cancel_workflow_execution(workflow_future)
558
- end
559
- end
560
- worker2 = WorkflowWorker.new(@swf.client, @domain, "new_child_workflow", OtherCancellationChildWorkflow)
561
- worker2.register
562
- worker = WorkflowWorker.new(@swf.client, @domain, "new_parent_workflow", BadCancellationChildWorkflow)
563
- worker.register
564
- client = workflow_client(@swf.client, @domain) { {:from_class => "BadCancellationChildWorkflow"} }
565
- workflow_execution = client.entry_point(5)
566
-
567
- worker.run_once
568
- worker2.run_once
569
- worker.run_once
570
- workflow_execution.events.map(&:event_type).should include "ExternalWorkflowExecutionCancelRequested"
571
- worker2.run_once
572
- workflow_execution.events.map(&:event_type).should include "ChildWorkflowExecutionCanceled"
573
- worker.run_once
574
- workflow_execution.events.to_a.last.attributes.details.should =~ /AWS::Flow::Core::Cancellation/
575
- end
540
+ # TODO: These three tests will sometimes fail, seemingly at random. We need to fix this.
541
+ # it "ensures that handle_child_workflow_execution_canceled is correct" do
542
+ # class OtherCancellationChildWorkflow
543
+ # extend Workflows
544
+ # workflow(:entry_point) { {:version => 1, :task_list => "new_child_workflow", :execution_start_to_close_timeout => 3600} }
545
+ # def entry_point(arg)
546
+ # create_timer(5)
547
+ # end
548
+ # end
549
+ # class BadCancellationChildWorkflow
550
+ # extend Workflows
551
+ # workflow(:entry_point) { {:version => 1, :task_list => "new_parent_workflow", :execution_start_to_close_timeout => 3600} }
552
+ # def other_entry_point
553
+ # end
576
554
 
577
- it "ensures that handle_child_workflow_terminated is handled correctly" do
578
- class OtherTerminationChildWorkflow
579
- extend Workflows
580
- workflow(:entry_point) { {:version => 1, :task_list => "new_child_workflow", :execution_start_to_close_timeout => 3600} }
555
+ # def entry_point(arg)
556
+ # client = workflow_client($swf.client, $domain) { {:from_class => "OtherCancellationChildWorkflow"} }
557
+ # workflow_future = client.send_async(:start_execution, 5)
558
+ # client.request_cancel_workflow_execution(workflow_future)
559
+ # end
560
+ # end
561
+ # worker2 = WorkflowWorker.new(@swf.client, @domain, "new_child_workflow", OtherCancellationChildWorkflow)
562
+ # worker2.register
563
+ # worker = WorkflowWorker.new(@swf.client, @domain, "new_parent_workflow", BadCancellationChildWorkflow)
564
+ # worker.register
565
+ # client = workflow_client(@swf.client, @domain) { {:from_class => "BadCancellationChildWorkflow"} }
566
+ # workflow_execution = client.entry_point(5)
567
+
568
+ # worker.run_once
569
+ # worker2.run_once
570
+ # worker.run_once
571
+ # workflow_execution.events.map(&:event_type).should include "ExternalWorkflowExecutionCancelRequested"
572
+ # worker2.run_once
573
+ # workflow_execution.events.map(&:event_type).should include "ChildWorkflowExecutionCanceled"
574
+ # worker.run_once
575
+ # workflow_execution.events.to_a.last.attributes.details.should =~ /AWS::Flow::Core::Cancellation/
576
+ # end
581
577
 
582
- def entry_point(arg)
583
- create_timer(5)
584
- end
578
+ # it "ensures that handle_child_workflow_terminated is handled correctly" do
579
+ # class OtherTerminationChildWorkflow
580
+ # extend Workflows
581
+ # workflow(:entry_point) { {:version => 1, :task_list => "new_child_workflow", :execution_start_to_close_timeout => 3600} }
585
582
 
586
- end
587
- $workflow_id = nil
588
- class BadTerminationChildWorkflow
589
- extend Workflows
590
- workflow(:entry_point) { {:version => 1, :task_list => "new_parent_workflow", :execution_start_to_close_timeout => 3600} }
591
- def other_entry_point
592
- end
583
+ # def entry_point(arg)
584
+ # create_timer(5)
585
+ # end
593
586
 
594
- def entry_point(arg)
595
- client = workflow_client($swf.client, $domain) { {:from_class => "OtherTerminationChildWorkflow"} }
596
- workflow_future = client.send_async(:start_execution, 5)
597
- $workflow_id = workflow_future.workflow_execution.workflow_id.get
598
- end
599
- end
600
- worker2 = WorkflowWorker.new(@swf.client, @domain, "new_child_workflow", OtherTerminationChildWorkflow)
601
- worker2.register
602
- worker = WorkflowWorker.new(@swf.client, @domain, "new_parent_workflow", BadTerminationChildWorkflow)
603
- worker.register
604
- client = workflow_client(@swf.client, @domain) { {:from_class => "BadTerminationChildWorkflow"} }
605
- workflow_execution = client.entry_point(5)
587
+ # end
588
+ # $workflow_id = nil
589
+ # class BadTerminationChildWorkflow
590
+ # extend Workflows
591
+ # workflow(:entry_point) { {:version => 1, :task_list => "new_parent_workflow", :execution_start_to_close_timeout => 3600} }
592
+ # def other_entry_point
593
+ # end
606
594
 
607
- worker.run_once
608
- worker2.run_once
609
- $swf.client.terminate_workflow_execution({:workflow_id => $workflow_id, :domain => $domain.name})
610
- worker.run_once
611
- workflow_execution.events.to_a.last.attributes.details.should =~ /AWS::Flow::ChildWorkflowTerminatedException/
612
- end
595
+ # def entry_point(arg)
596
+ # client = workflow_client($swf.client, $domain) { {:from_class => "OtherTerminationChildWorkflow"} }
597
+ # workflow_future = client.send_async(:start_execution, 5)
598
+ # $workflow_id = workflow_future.workflow_execution.workflow_id.get
599
+ # end
600
+ # end
601
+ # worker2 = WorkflowWorker.new(@swf.client, @domain, "new_child_workflow", OtherTerminationChildWorkflow)
602
+ # worker2.register
603
+ # worker = WorkflowWorker.new(@swf.client, @domain, "new_parent_workflow", BadTerminationChildWorkflow)
604
+ # worker.register
605
+ # client = workflow_client(@swf.client, @domain) { {:from_class => "BadTerminationChildWorkflow"} }
606
+ # workflow_execution = client.entry_point(5)
607
+
608
+ # worker.run_once
609
+ # worker2.run_once
610
+ # $swf.client.terminate_workflow_execution({:workflow_id => $workflow_id, :domain => $domain.name})
611
+ # worker.run_once
612
+ # workflow_execution.events.to_a.last.attributes.details.should =~ /AWS::Flow::ChildWorkflowTerminatedException/
613
+ # end
613
614
 
614
- it "ensures that handle_child_workflow_timed_out is handled correctly" do
615
- class OtherTimedOutChildWorkflow
616
- extend Workflows
617
- workflow(:entry_point) { {:version => 1, :task_list => "new_child_workflow", :execution_start_to_close_timeout => 5} }
615
+ # it "ensures that handle_child_workflow_timed_out is handled correctly" do
616
+ # class OtherTimedOutChildWorkflow
617
+ # extend Workflows
618
+ # workflow(:entry_point) { {:version => 1, :task_list => "new_child_workflow", :execution_start_to_close_timeout => 5} }
618
619
 
619
- def entry_point(arg)
620
- create_timer(5)
621
- end
620
+ # def entry_point(arg)
621
+ # create_timer(5)
622
+ # end
622
623
 
623
- end
624
- $workflow_id = nil
625
- class BadTimedOutChildWorkflow
626
- extend Workflows
627
- workflow(:entry_point) { {:version => 1, :task_list => "new_parent_workflow", :execution_start_to_close_timeout => 3600} }
628
- def other_entry_point
629
- end
624
+ # end
625
+ # $workflow_id = nil
626
+ # class BadTimedOutChildWorkflow
627
+ # extend Workflows
628
+ # workflow(:entry_point) { {:version => 1, :task_list => "new_parent_workflow", :execution_start_to_close_timeout => 3600} }
629
+ # def other_entry_point
630
+ # end
630
631
 
631
- def entry_point(arg)
632
- client = workflow_client($swf.client, $domain) { {:from_class => "OtherTimedOutChildWorkflow"} }
633
- workflow_future = client.send_async(:start_execution, 5)
634
- $workflow_id = workflow_future.workflow_execution.workflow_id.get
635
- end
636
- end
637
- worker2 = WorkflowWorker.new(@swf.client, @domain, "new_child_workflow", OtherTimedOutChildWorkflow)
638
- worker2.register
639
- worker = WorkflowWorker.new(@swf.client, @domain, "new_parent_workflow", BadTimedOutChildWorkflow)
640
- worker.register
641
- client = workflow_client(@swf.client, @domain) { {:from_class => "BadTimedOutChildWorkflow"} }
642
- workflow_execution = client.entry_point(5)
643
- worker.run_once
644
- sleep 8
645
- worker.run_once
646
- workflow_execution.events.to_a.last.attributes.details.should =~ /AWS::Flow::ChildWorkflowTimedOutException/
647
- end
632
+ # def entry_point(arg)
633
+ # client = workflow_client($swf.client, $domain) { {:from_class => "OtherTimedOutChildWorkflow"} }
634
+ # workflow_future = client.send_async(:start_execution, 5)
635
+ # $workflow_id = workflow_future.workflow_execution.workflow_id.get
636
+ # end
637
+ # end
638
+ # worker2 = WorkflowWorker.new(@swf.client, @domain, "new_child_workflow", OtherTimedOutChildWorkflow)
639
+ # worker2.register
640
+ # worker = WorkflowWorker.new(@swf.client, @domain, "new_parent_workflow", BadTimedOutChildWorkflow)
641
+ # worker.register
642
+ # client = workflow_client(@swf.client, @domain) { {:from_class => "BadTimedOutChildWorkflow"} }
643
+ # workflow_execution = client.entry_point(5)
644
+ # worker.run_once
645
+ # sleep 8
646
+ # worker.run_once
647
+ # workflow_execution.events.to_a.last.attributes.details.should =~ /AWS::Flow::ChildWorkflowTimedOutException/
648
+ # end
648
649
 
649
650
  it "ensures that handle_timer_canceled is fine" do
650
651
  general_test(:task_list => "handle_timer_canceled", :class_name => "HandleTimerCanceled")
@@ -1802,7 +1803,7 @@ describe "RubyFlowDecider" do
1802
1803
  # We use an executor here so as to be able to test this feature within one
1803
1804
  # working process, as activity_worker.start and worker.start will block
1804
1805
  # otherwise
1805
- forking_executor = ForkingExecutor.new
1806
+ forking_executor = ForkingExecutor.new(:max_workers => 2)
1806
1807
  forking_executor.execute { activity_worker.start }
1807
1808
  forking_executor.execute { worker.start }
1808
1809
 
@@ -1903,7 +1904,7 @@ describe "RubyFlowDecider" do
1903
1904
  # avoid them by putting in a small sleep. There is no plan to fix at current, as
1904
1905
  # we don't expect forking executor to be used by most customers.
1905
1906
  sleep 5
1906
- forking_executor = ForkingExecutor.new
1907
+ forking_executor = ForkingExecutor.new(:max_workers => 2)
1907
1908
 
1908
1909
  forking_executor.execute { activity_worker.start }
1909
1910
  sleep 5
@@ -3104,5 +3105,55 @@ describe "RubyFlowDecider" do
3104
3105
  client = workflow_client(swf.client, domain) { {:from_class => WorkflowWorkflow} }
3105
3106
  client.is_execution_method(:entry_point).should == true
3106
3107
  end
3108
+ it "tests whether a forking executor will not accept work when it has no free workers" do
3109
+ swf, domain, _ = setup_swf
3110
+
3111
+ class ForkingTestActivity
3112
+ extend Activity
3113
+ activity(:activity1) do
3114
+ {
3115
+ :version => 1,
3116
+ :default_task_list => "forking_executor_test",
3117
+ :default_task_schedule_to_start_timeout => 120,
3118
+ :default_task_start_to_close_timeout => 120,
3119
+ :default_task_heartbeat_timeout => "3600"
3120
+ }
3121
+ end
3122
+ def activity1; sleep 10; end
3123
+ end
3124
+ class ForkingTestWorkflow
3125
+ extend Workflows
3126
+ workflow(:entry_point) { {:version => "1", :execution_start_to_close_timeout => 3600, :task_list => "forking_executor_test"} }
3127
+ activity_client(:activity) { {:version => "1", :from_class => ForkingTestActivity} }
3128
+ def entry_point
3129
+ 3.times { activity.send_async(:activity1) }
3130
+ end
3131
+ end
3132
+
3133
+ worker = WorkflowWorker.new(swf.client, domain, "forking_executor_test", ForkingTestWorkflow)
3134
+ worker.register
3135
+
3136
+ activity_worker = ActivityWorker.new(swf.client, domain, "forking_executor_test", ForkingTestActivity) { { :execution_workers => 1 } }
3137
+ activity_worker.register
3138
+
3139
+ client = workflow_client(swf.client, domain) { {:from_class => ForkingTestWorkflow} }
3140
+
3141
+ workflow_execution = client.start_execution
3142
+ forking_executor = ForkingExecutor.new(:max_workers => 3)
3143
+ forking_executor.execute { worker.start }
3144
+ forking_executor.execute { activity_worker.start }
3145
+ sleep 20
3146
+ history = workflow_execution.events.map(&:event_type)
3147
+ current_depth = 0
3148
+ 0.upto(history.length) do |i|
3149
+ current_depth += 1 if history[i] == "ActivityTaskStarted"
3150
+ current_depth -= 1 if (history[i] =~ /ActivityTask(Completed|TimedOut|Failed)/)
3151
+ if current_depth > 1
3152
+ raise "We had two started's in a row, which indicates the possibility of starving(since the worker should only process one activity at a time) and thus causing a task timeout"
3153
+ end
3154
+ end
3155
+
3156
+ end
3157
+
3107
3158
  end
3108
3159
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws-flow
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-08-14 00:00:00.000000000 Z
12
+ date: 2013-10-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: aws-sdk
@@ -32,17 +32,17 @@ dependencies:
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  none: false
34
34
  requirements:
35
- - - ~>
35
+ - - ! '>='
36
36
  - !ruby/object:Gem::Version
37
- version: '1'
37
+ version: 1.0.1
38
38
  type: :runtime
39
39
  prerelease: false
40
40
  version_requirements: !ruby/object:Gem::Requirement
41
41
  none: false
42
42
  requirements:
43
- - - ~>
43
+ - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
- version: '1'
45
+ version: 1.0.1
46
46
  description: Library to provide the AWS Flow Framework for Ruby
47
47
  email: ''
48
48
  executables: []