dynosaur 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4143dd8410c842565956f544fca8c5edcfc2752c
4
- data.tar.gz: 4d24ef4ccbc6a6fe6742da89b1f39585f7c0759f
3
+ metadata.gz: 1448d342f89404da10452e0e95176627f5c7ed56
4
+ data.tar.gz: ffe0d95b07ad64c410d89e4645289faa107c7cf5
5
5
  SHA512:
6
- metadata.gz: c153e19d0bdeea037f565d44a2bec05d8c2e8911eb2c4e73f39ca53ec9ba73d12bf1b4c6f795705eb11d48c635a503d567ad84988e5c2350f14b1de45ed26975
7
- data.tar.gz: f7257bd138dc326167639de8665e018bc2d216b9c2746c268b8d41a530abbb781cbbc11d874467cb2e4e0966635e979fc4beb28ba7cc3bc5ee3031c66973cb75
6
+ metadata.gz: 06a80b1d43a568785eee94acab44b02a260d4a61e83bd2502886ab2abd1dc0c2c9bf647b37b8a23ddec22a260455024a66ffd4192df89fdb7139af767387cfce
7
+ data.tar.gz: f0d630594d61500d65d7eafa207c33c36ac622d5af7f89fd63ebb0d7c6dda2649aa7ca20a1c65bcd198f92acf8bb4b4aaeaa2ad20bea3e9ff3593ffd0e18c030
data/README.md CHANGED
@@ -35,6 +35,13 @@ local_process.start
35
35
  # => 48345
36
36
  ```
37
37
 
38
+ You can also check to see if a similar rake task is already running before starting
39
+ the task (e.g. if you want at most one instance of that task running concurrently)
40
+
41
+ ```ruby
42
+ dyno = Dynosaur::Process::Heroku.new(task: 'session:destroy', args: [2500])
43
+ dyno.start unless dyno.running?
44
+ ```
38
45
 
39
46
  ## Development
40
47
 
data/Rakefile CHANGED
@@ -5,22 +5,3 @@ require 'rspec/core/rake_task'
5
5
  RSpec::Core::RakeTask.new(:spec)
6
6
 
7
7
  task default: :spec
8
-
9
- task :echo, [:arg1, :arg2] do |_task, args|
10
- puts %Q(ARG1: "#{args[:arg1]}")
11
- puts %Q(ARG2: "#{args[:arg2]}")
12
- end
13
-
14
- task :sleep, [:duration] do |_task, args|
15
- File.open('/tmp/sleep', 'w') do |file|
16
- file.puts "Sleeping"
17
- args[:duration].to_i.times do
18
- sleep(1)
19
- file.print('.')
20
- file.flush
21
- end
22
- file.print("\n")
23
- file.puts "Awake"
24
- file.flush
25
- end
26
- end
@@ -0,0 +1,34 @@
1
+ # Detects if a running dyno is currently executing the rake command
2
+ module Dynosaur
3
+ class Process
4
+ class Heroku
5
+ class Finder
6
+ def initialize(rake_command:, client: Client::HerokuClient.client)
7
+ @rake_command = rake_command
8
+ @client = client
9
+ end
10
+
11
+ def exists?
12
+ one_off_dynos.any? do |dyno|
13
+ Utils::RakeCommand.valid?(dyno.command) &&
14
+ Utils::RakeCommand.parse(dyno.command) == rake_command
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :rake_command, :client
21
+
22
+ # @return [Array] Object instances, which respond to #command, for all
23
+ # locally one off dynos
24
+ def one_off_dynos
25
+ app_name = Dynosaur::Client::HerokuClient.app_name
26
+ dynos = client.dyno.list(app_name).map do |response|
27
+ Struct.new(:type, :command).new(response['type'], response['command'])
28
+ end
29
+ dynos.select { |dyno| dyno.type == 'run' }
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -1,7 +1,5 @@
1
1
  require 'dynosaur/client/heroku_client'
2
2
 
3
- require_relative '../process'
4
-
5
3
  # Start a detached rake task on a one-off dyno
6
4
  module Dynosaur
7
5
  class Process
@@ -23,10 +21,10 @@ module Dynosaur
23
21
 
24
22
  def start
25
23
  app_name = Dynosaur::Client::HerokuClient.app_name
26
- dyno_accessor = Dynosaur::Client::HerokuClient.client.dyno
27
- create_opts = { command: rake_command, attach: false }
24
+ client = Dynosaur::Client::HerokuClient.client
25
+ create_opts = { command: rake_command.to_s, attach: false }
28
26
  create_opts[:size] = size if size
29
- response = dyno_accessor.create(app_name, create_opts)
27
+ response = client.dyno.create(app_name, create_opts)
30
28
  response['name']
31
29
  end
32
30
 
@@ -0,0 +1,23 @@
1
+ # Detects if a running process is currently executing the rake command
2
+ module Dynosaur
3
+ class Process
4
+ class Local
5
+ class Finder
6
+ def initialize(rake_command:)
7
+ @rake_command = rake_command
8
+ end
9
+
10
+ def exists?
11
+ Utils::OS.structured_ps.any? do |process|
12
+ Utils::RakeCommand.valid?(process.command) &&
13
+ Utils::RakeCommand.parse(process.command) == rake_command
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :rake_command
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,10 +1,9 @@
1
- require_relative '../process'
2
-
1
+ # Start the rake task in a local process
3
2
  module Dynosaur
4
3
  class Process
5
4
  class Local < Process
6
5
  def start
7
- pid = ::Process.spawn(rake_command)
6
+ pid = ::Process.spawn(rake_command.to_s)
8
7
  ::Process.detach(pid)
9
8
  pid
10
9
  end
@@ -3,29 +3,26 @@ require 'shellwords'
3
3
  module Dynosaur
4
4
  class Process
5
5
  def initialize(task:, args: [], opts: {})
6
- @task = task
7
- @args = args
6
+ @rake_command = Utils::RakeCommand.new(task: task, args: args)
8
7
  after_initialize(opts)
9
8
  end
10
9
 
10
+ def running?
11
+ klass = self.class.const_get('Finder')
12
+ finder = klass.new(rake_command: rake_command)
13
+ finder.exists?
14
+ end
15
+
11
16
  def start
12
17
  fail NotImplementedError, 'This method must be implemented in a subclass'
13
18
  end
14
19
 
15
20
  private
16
21
 
17
- attr_reader :args, :task
22
+ attr_reader :rake_command
18
23
 
19
24
  def after_initialize(opts)
20
25
  # Do nothing so subclasses don't have to override if they want a no-op
21
26
  end
22
-
23
- def rake_command
24
- formatted_args = args.map do |arg|
25
- arg.is_a?(String) ? arg.shellescape : arg
26
- end.join(',')
27
- task_with_args = args.empty? ? task : "#{task}[#{formatted_args}]"
28
- "rake #{task_with_args} --trace"
29
- end
30
27
  end
31
28
  end
@@ -0,0 +1,24 @@
1
+ # Utility methods for interacting with the underlying OS
2
+ module Dynosaur
3
+ module Utils
4
+ module OS
5
+ class << self
6
+ # @return [Array] Object instances, which respond to #command, for all
7
+ # locally running processes returned by the ps command
8
+ def structured_ps
9
+ ps_array = command_ps.split("\n").map(&:strip)
10
+ ps_array.shift # Remove the header row
11
+ ps_array.map do |command|
12
+ Struct.new(:command).new(command)
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def command_ps
19
+ `ps -o command`
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,45 @@
1
+ # Utility methods for generating and parsing rake command
2
+ module Dynosaur
3
+ module Utils
4
+ class RakeCommand
5
+ PARSE_REGEX = /\brake\s+([\w:]+)(\[.*\])?/
6
+
7
+ attr_reader :task, :args
8
+
9
+ # @param command [String] the command to test for validity
10
+ # @return [true|false] true iff the string is a valid rake command
11
+ def self.valid?(command)
12
+ !(command =~ PARSE_REGEX).nil?
13
+ end
14
+
15
+ # @param command [String] the command to parse
16
+ # @return [RakeCommand] an instance that represents the command being parsed
17
+ # @raise [ArgumentError] if the command is not a valid rake command
18
+ def self.parse(command)
19
+ match = command.match(PARSE_REGEX)
20
+ raise ArgumentError, %Q(Invalid rake command: "#{command}") unless match
21
+ task = match[1]
22
+ args = match[2] ? match[2].tr('[]', '').split(',') : []
23
+ new(task: task, args: args)
24
+ end
25
+
26
+ def initialize(task:, args: [])
27
+ @task = task
28
+ @args = args
29
+ end
30
+
31
+ # @return [String] the full rake command, including arguments
32
+ def to_s
33
+ formatted_args = args.map do |arg|
34
+ arg.is_a?(String) ? arg.shellescape : arg
35
+ end.join(',')
36
+ task_with_args = args.empty? ? task : "#{task}[#{formatted_args}]"
37
+ "rake #{task_with_args} --trace"
38
+ end
39
+
40
+ def ==(other)
41
+ task == other.task && args.map(&:to_s) == other.args.map(&:to_s)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -1,4 +1,4 @@
1
1
  # Gem version number
2
2
  module Dynosaur
3
- VERSION = '0.1.0'
3
+ VERSION = '0.2.0'
4
4
  end
data/lib/dynosaur.rb CHANGED
@@ -1,6 +1,13 @@
1
1
  require 'dynosaur/version'
2
+
3
+ require 'dynosaur/process'
2
4
  require 'dynosaur/process/heroku'
5
+ require 'dynosaur/process/heroku/finder'
3
6
  require 'dynosaur/process/local'
7
+ require 'dynosaur/process/local/finder'
8
+
9
+ require 'dynosaur/utils/os'
10
+ require 'dynosaur/utils/rake_command'
4
11
 
5
12
  # Spin up a rake task in a separate process
6
13
  module Dynosaur
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dynosaur
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Collier
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-11-10 00:00:00.000000000 Z
11
+ date: 2015-12-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: platform-api
@@ -117,7 +117,11 @@ files:
117
117
  - lib/dynosaur/client/heroku_client.rb
118
118
  - lib/dynosaur/process.rb
119
119
  - lib/dynosaur/process/heroku.rb
120
+ - lib/dynosaur/process/heroku/finder.rb
120
121
  - lib/dynosaur/process/local.rb
122
+ - lib/dynosaur/process/local/finder.rb
123
+ - lib/dynosaur/utils/os.rb
124
+ - lib/dynosaur/utils/rake_command.rb
121
125
  - lib/dynosaur/version.rb
122
126
  homepage:
123
127
  licenses: