lambda_whenever 0.1.1 → 0.3.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 67a5c5474ef6496852336282c2a377f9f6c0063d0ab366c0af32ccaf2913c379
4
- data.tar.gz: f823d4e7f110f729553ea01187c712d6adb0b3a85b1edbb97218fd95b64f1cd6
3
+ metadata.gz: 5f129b23aca4d25d6b995c09a9d1644a6d8f510f2a620996168ca2eff79a292d
4
+ data.tar.gz: ec91d0520bb573d4f630bfe8b07fc7fbe4a15b41930ea6aaeb146046c4ae24e9
5
5
  SHA512:
6
- metadata.gz: 14ecdce83d2156801ddd4af596ba084dbd5a1741b97f74c39bd64d541df34573a070c56fd18dc628678069551c0f8d0befeea4721ec3110fee3cb4c23d370212
7
- data.tar.gz: 1239df92546e75453eb7ead19baf439515451e80ae538a11f9b926648bc74b146af06d70f75afc2ed1f520bfa57ea76a3bfb53a603a1267afb548ae3a2cf9c1d
6
+ metadata.gz: 900fd11c932e0620aea048f497be0b59655e45422953794fa13fc0ae149ad0662d9832de3283ede985ffec566ec8eacc74c01c2f20991621cdd5f1f7a75933f1
7
+ data.tar.gz: df722523f0dca951232658b021f4ad81cf9d320fabd0fedcc866a04a407a59c69210df9ac4431ba01d8d9451251dcc44c879ba2f921924961714ed6deb78074d
@@ -26,6 +26,12 @@ module LambdaWhenever
26
26
  update_eb_schedules
27
27
  end
28
28
  Logger.instance.log("write", "scheduled tasks updated")
29
+ when Option::SYNC_MODE
30
+ option.validate!
31
+ with_concurrent_modification_handling do
32
+ sync_eb_schedules
33
+ end
34
+ Logger.instance.log("write", "scheduled tasks updated")
29
35
  when Option::CLEAR_MODE
30
36
  with_concurrent_modification_handling do
31
37
  clear_tasks
@@ -68,6 +74,26 @@ module LambdaWhenever
68
74
  end
69
75
  end
70
76
 
77
+ def sync_eb_schedules
78
+ schedule = Schedule.new(option.schedule_file, option.verbose, option.variables)
79
+ scheduler = EventBridgeScheduler.new(option.scheduler_client, schedule.timezone)
80
+
81
+ scheduler.create_schedule_group(option.scheduler_group)
82
+
83
+ current_schedules = scheduler.list_schedules(option.scheduler_group)
84
+ lambda_arn = TargetLambda.fetch_arn(option.lambda_name, option.lambda_client)
85
+ desired_schedules = schedule.tasks.map do |task|
86
+ target = TargetLambda.new(arn: lambda_arn, task: task)
87
+ {
88
+ name: scheduler.schedule_name(task, option),
89
+ target: target,
90
+ task: task
91
+ }
92
+ end
93
+
94
+ scheduler.sync_schedules(desired_schedules, current_schedules, option)
95
+ end
96
+
71
97
  def clear_tasks
72
98
  scheduler = EventBridgeScheduler.new(option.scheduler_client)
73
99
  scheduler.clean_up_schedules(option.scheduler_group)
@@ -13,17 +13,60 @@ module LambdaWhenever
13
13
  def list_schedules(group_name)
14
14
  Logger.instance.message("Schedules in group '#{group_name}':")
15
15
  response = @scheduler_client.list_schedules({ group_name: group_name })
16
- response.schedules.each do |schedule|
16
+ response.schedules.map do |schedule|
17
17
  detail = @scheduler_client.get_schedule({ group_name: group_name, name: schedule.name })
18
- puts "#{schedule.state} #{schedule.name} #{detail.schedule_expression} #{detail.description}"
18
+ Logger.instance.message "#{schedule.state} #{schedule.name} #{detail.schedule_expression} #{detail.description}"
19
+ {
20
+ name: schedule.name,
21
+ state: schedule.state,
22
+ expression: detail.schedule_expression,
23
+ description: detail.description
24
+ }
25
+ end
26
+ end
27
+
28
+ def sync_schedules(desired_schedules, current_schedules, option)
29
+ desired_names = desired_schedules.map { |s| s[:name] }.to_set
30
+ current_schedules_hash = current_schedules.to_h do |schedule|
31
+ [schedule[:name], schedule]
32
+ end
33
+ current_names = current_schedules_hash.keys.to_set
34
+ to_delete = current_names - desired_names
35
+
36
+ to_add, to_update = desired_schedules.each_with_object([[], []]) do |desired, (add, update)|
37
+ current = current_schedules_hash[desired[:name]]
38
+ if current.nil?
39
+ add << desired
40
+ elsif schedules_differ?(current, desired, option)
41
+ update << desired
42
+ end
43
+ end
44
+
45
+ Logger.instance.message("Deleting #{to_delete.length} schedules...")
46
+ to_delete.each do |name|
47
+ Logger.instance.message "delete schedule: #{name}"
48
+ delete_schedule(name, option.scheduler_group)
49
+ end
50
+
51
+ Logger.instance.message("Creating #{to_add.length} schedules...")
52
+ to_add.each do |schedule|
53
+ Logger.instance.message "create schedule: #{schedule[:name]}"
54
+ create_schedule(schedule[:target], option)
55
+ end
56
+
57
+ Logger.instance.message("Updating #{to_update.length} schedules...")
58
+ to_update.each do |desired|
59
+ Logger.instance.message("Updating schedule: #{desired[:name]}")
60
+ delete_schedule(desired[:name], option.scheduler_group)
61
+ create_schedule(desired[:target], option)
19
62
  end
20
63
  end
21
64
 
22
65
  def create_schedule_group(group_name)
23
66
  @scheduler_client.create_schedule_group({ name: group_name })
24
- puts "Schedule group '#{group_name}' created."
67
+ Logger.instance.message "Schedule group '#{group_name}' created."
25
68
  rescue Aws::Scheduler::Errors::ConflictException
26
- puts "Schedule group '#{group_name}' already exists."
69
+ Logger.instance.message "Schedule group '#{group_name}' already exists."
27
70
  end
28
71
 
29
72
  # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/Scheduler/Client.html#create_schedule-instance_method
@@ -49,7 +92,8 @@ module LambdaWhenever
49
92
  end
50
93
 
51
94
  def schedule_name(task, option)
52
- Digest::SHA1.hexdigest([option.key, task.expression, *task.commands].join("-")).to_s[0, 64]
95
+ input = "#{task.name}-#{Digest::SHA1.hexdigest([option.key, task.expression, *task.commands].join("-"))}"
96
+ sanitize_and_trim(input)
53
97
  end
54
98
 
55
99
  def schedule_description(task)
@@ -59,13 +103,31 @@ module LambdaWhenever
59
103
  def clean_up_schedules(schedule_group)
60
104
  response = @scheduler_client.list_schedules({ group_name: schedule_group })
61
105
  response.schedules.each do |schedule|
62
- @scheduler_client.delete_schedule({
63
- name: schedule.name,
64
- group_name: schedule_group
65
- })
106
+ delete_schedule(schedule.name, schedule_group)
66
107
  end
108
+ end
109
+
110
+ private
111
+
112
+ def sanitize_and_trim(input)
113
+ sanitized = input.gsub(/[^a-zA-Z0-9\-._]/, "_")
114
+ sanitized[0, 64]
115
+ end
116
+
117
+ def schedules_differ?(current, desired, option)
118
+ task = desired[:target].task
119
+ current[:expression] != task.expression ||
120
+ current[:description] != schedule_description(task) ||
121
+ current[:state] != option.rule_state
122
+ end
123
+
124
+ def delete_schedule(name, group_name)
125
+ @scheduler_client.delete_schedule({
126
+ name: name,
127
+ group_name: group_name
128
+ })
67
129
  rescue Aws::Scheduler::Errors::ResourceNotFoundException
68
- puts "Schedule group '#{schedule_group}' does not exist."
130
+ Logger.instance.message("Schedule '#{name}' does not exist.")
69
131
  end
70
132
  end
71
133
  end
@@ -10,6 +10,7 @@ module LambdaWhenever
10
10
  CLEAR_MODE = 3
11
11
  LIST_MODE = 4
12
12
  PRINT_VERSION_MODE = 5
13
+ SYNC_MODE = 6
13
14
 
14
15
  attr_reader :mode, :verbose, :variables, :schedule_file, :iam_role, :rule_state,
15
16
  :lambda_name, :scheduler_group
@@ -31,9 +32,12 @@ module LambdaWhenever
31
32
  opts.on("--dryrun", "dry-run") do
32
33
  @mode = DRYRUN_MODE
33
34
  end
34
- opts.on("--update", "Creates and deletes tasks as needed by schedule file") do
35
+ opts.on("--update", "clear and create schedules") do
35
36
  @mode = UPDATE_MODE
36
37
  end
38
+ opts.on("--sync", "Creates and deletes tasks as needed by schedule file") do
39
+ @mode = SYNC_MODE
40
+ end
37
41
  opts.on("-c", "--clear", "Clear scheduled tasks") do
38
42
  @mode = CLEAR_MODE
39
43
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module LambdaWhenever
4
4
  class Task
5
- attr_reader :commands, :expression
5
+ attr_reader :commands, :expression, :name
6
6
 
7
7
  def initialize(environment, verbose, bundle_command, expression)
8
8
  @environment = environment
@@ -10,6 +10,7 @@ module LambdaWhenever
10
10
  @bundle_command = bundle_command.split(" ")
11
11
  @expression = expression
12
12
  @commands = []
13
+ @name = ""
13
14
  end
14
15
 
15
16
  def command(task)
@@ -17,14 +18,17 @@ module LambdaWhenever
17
18
  end
18
19
 
19
20
  def rake(task)
20
- @commands << [@bundle_command, "rake", task, @verbose_mode].flatten.compact
21
+ @name = task
22
+ @commands << [*@bundle_command, "rake", task, *@verbose_mode]
21
23
  end
22
24
 
23
25
  def runner(src)
26
+ @name = src
24
27
  @commands << [@bundle_command, "rails", "runner", "-e", @environment, src].flatten
25
28
  end
26
29
 
27
30
  def script(script)
31
+ @name = script
28
32
  @commands << [@bundle_command, "script/#{script}"].flatten
29
33
  end
30
34
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LambdaWhenever
4
- VERSION = "0.1.1"
4
+ VERSION = "0.3.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lambda_whenever
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - toshichanapp
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-09-03 00:00:00.000000000 Z
11
+ date: 2024-12-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -224,7 +224,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
224
224
  - !ruby/object:Gem::Version
225
225
  version: '0'
226
226
  requirements: []
227
- rubygems_version: 3.5.11
227
+ rubygems_version: 3.5.22
228
228
  signing_key:
229
229
  specification_version: 4
230
230
  summary: whenever for Amazon EventBridge Scheduler.