execache 0.1.1 → 0.1.2

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.
data/.gitignore CHANGED
@@ -1,6 +1,7 @@
1
1
  .DS_Store
2
2
  *.gem
3
3
  .bundle
4
+ dump.rdb
4
5
  Gemfile.lock
5
6
  pkg
6
7
  tmp
data/execache.gemspec CHANGED
@@ -6,7 +6,7 @@ $:.unshift lib unless $:.include?(lib)
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "execache"
9
- s.version = '0.1.1'
9
+ s.version = '0.1.2'
10
10
  s.platform = Gem::Platform::RUBY
11
11
  s.authors = [ "Winton Welsh" ]
12
12
  s.email = [ "mail@wintoni.us" ]
@@ -9,18 +9,29 @@ class Execache
9
9
  end
10
10
 
11
11
  def exec(options)
12
- options[:channel] = Digest::SHA1.hexdigest("#{rand}")
12
+ wait = options.delete(:wait)
13
+ subscribe_to = options[:channel] = Digest::SHA1.hexdigest("#{rand}")
14
+ options = Yajl::Encoder.encode(options)
13
15
  response = nil
14
16
 
15
17
  Timeout.timeout(60) do
16
- @redis_1.subscribe("execache:response:#{options[:channel]}") do |on|
18
+ @redis_1.subscribe("execache:response:#{subscribe_to}") do |on|
17
19
  on.subscribe do |channel, subscriptions|
18
- @redis_2.rpush "execache:request", Yajl::Encoder.encode(options)
20
+ @redis_2.rpush "execache:request", options
19
21
  end
20
22
 
21
23
  on.message do |channel, message|
22
- response = Yajl::Parser.parse(message)
23
- @redis_1.unsubscribe
24
+ if message.include?('[PENDING]')
25
+ if wait == false
26
+ response = false
27
+ @redis_1.unsubscribe
28
+ else
29
+ @redis_2.rpush "execache:request", options
30
+ end
31
+ else
32
+ response = Yajl::Parser.parse(message)
33
+ @redis_1.unsubscribe
34
+ end
24
35
  end
25
36
  end
26
37
  end
data/lib/execache.rb CHANGED
@@ -26,10 +26,11 @@ class Execache
26
26
  while true
27
27
  request = redis.lpop('execache:request')
28
28
  if request
29
- Thread.new do
29
+ Timeout.timeout(60) do
30
30
  request = Yajl::Parser.parse(request)
31
31
  channel = request.delete('channel')
32
32
  commands = []
33
+ pending = false
33
34
 
34
35
  request.each do |cmd_type, cmd_options|
35
36
  # Command with preliminary args
@@ -46,11 +47,14 @@ class Execache
46
47
  group['cache_key'] = cache_key = "execache:cache:#{cache_key}"
47
48
  cache = redis.get(cache_key)
48
49
 
49
- if cache
50
+ if cache && cache == '[PENDING]'
51
+ pending = true
52
+ elsif cache
50
53
  group['result'] = Yajl::Parser.parse(cache)
51
54
  else
55
+ pending = true
56
+ redis.set(cache_key, '[PENDING]')
52
57
  command << group['args']
53
- nil
54
58
  end
55
59
  end
56
60
 
@@ -60,40 +64,49 @@ class Execache
60
64
  end
61
65
  end
62
66
 
63
- # Build response
64
- response = request.inject({}) do |hash, (cmd_type, cmd_options)|
65
- hash[cmd_type] = []
67
+ if pending
68
+ # Execute command in thread, cache results
69
+ Thread.new do
70
+ Timeout.timeout(60) do
71
+ request.each do |cmd_type, cmd_options|
72
+ if cmd_options['cmd']
73
+ separators = options[cmd_type]['separators'] || {}
74
+ separators['group'] ||= "[END]"
75
+ separators['result'] ||= "\n"
76
+ output = `#{cmd_options['cmd']}`
77
+ output = output.split(separators['group'] + separators['result'])
78
+ output = output.collect { |r| r.split(separators['result']) }
79
+ end
66
80
 
67
- if cmd_options['cmd']
68
- separators = options[cmd_type]['separators'] || {}
69
- separators['group'] ||= "[END]"
70
- separators['result'] ||= "\n"
71
- output = `#{cmd_options['cmd']}`
72
- output = output.split(separators['group'] + separators['result'])
73
- output = output.collect { |r| r.split(separators['result']) }
81
+ cmd_options['groups'].each do |group|
82
+ unless group['result']
83
+ redis.set(
84
+ group['cache_key'],
85
+ Yajl::Encoder.encode(output.shift)
86
+ )
87
+ if group['ttl']
88
+ redis.expire(group['cache_key'], group['ttl'])
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
74
94
  end
95
+ else
96
+ response = request.inject({}) do |hash, (cmd_type, cmd_options)|
97
+ hash[cmd_type] = []
75
98
 
76
- cmd_options['groups'].each do |group|
77
- if group['result']
99
+ cmd_options['groups'].each do |group|
78
100
  hash[cmd_type] << group['result']
79
- else
80
- hash[cmd_type] << output.shift
81
- redis.set(
82
- group['cache_key'],
83
- Yajl::Encoder.encode(hash[cmd_type].last)
84
- )
85
- if group['ttl']
86
- redis.expire(group['cache_key'], group['ttl'])
87
- end
88
101
  end
89
- end
90
102
 
91
- hash
103
+ hash
104
+ end
92
105
  end
93
106
 
94
107
  redis.publish(
95
108
  "execache:response:#{channel}",
96
- Yajl::Encoder.encode(response)
109
+ pending ? '[PENDING]' : Yajl::Encoder.encode(response)
97
110
  )
98
111
  end
99
112
  end
@@ -2,21 +2,23 @@ require 'spec_helper'
2
2
 
3
3
  describe Execache do
4
4
 
5
- def client_exec
5
+ def client_exec(options={})
6
6
  @client.exec(
7
- :some_binary => {
8
- :args => 'preliminary_arg',
9
- :groups => [
10
- {
11
- :args => 'arg1a arg1b',
12
- :ttl => 60
13
- },
14
- {
15
- :args => 'arg2a arg2b',
16
- :ttl => 60
17
- }
18
- ]
19
- }
7
+ {
8
+ :some_binary => {
9
+ :args => 'preliminary_arg',
10
+ :groups => [
11
+ {
12
+ :args => 'arg1a arg1b',
13
+ :ttl => 60
14
+ },
15
+ {
16
+ :args => 'arg2a arg2b',
17
+ :ttl => 60
18
+ }
19
+ ]
20
+ }
21
+ }.merge(options)
20
22
  )
21
23
  end
22
24
 
@@ -120,4 +122,17 @@ describe Execache do
120
122
  ]
121
123
  }
122
124
  end
125
+
126
+ it "should respect wait option" do
127
+ @client.redis_1.keys("execache:cache:*").each do |key|
128
+ @client.redis_1.del(key)
129
+ end
130
+ client_exec(:wait => false).should == false
131
+ client_exec.should == {
132
+ "some_binary" => [
133
+ ["arg1_result_1", "arg1_result_2"],
134
+ ["arg2_result_1", "arg2_result_2"]
135
+ ]
136
+ }
137
+ end
123
138
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: execache
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-10-11 00:00:00.000000000Z
12
+ date: 2011-10-14 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &70277360546840 !ruby/object:Gem::Requirement
16
+ requirement: &70246699607900 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '1.0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70277360546840
24
+ version_requirements: *70246699607900
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: redis
27
- requirement: &70277360546360 !ruby/object:Gem::Requirement
27
+ requirement: &70246699607420 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 2.2.2
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70277360546360
35
+ version_requirements: *70246699607420
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: yajl-ruby
38
- requirement: &70277360545900 !ruby/object:Gem::Requirement
38
+ requirement: &70246699606960 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: 1.0.0
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70277360545900
46
+ version_requirements: *70246699606960
47
47
  description: Run commands in parallel and cache the output. Redis queues jobs and
48
48
  stores the result.
49
49
  email: