@@ -208,6 +208,10 @@ class Agent < ActiveRecord::Base |
||
208 | 208 |
self.class.can_dry_run? |
209 | 209 |
end |
210 | 210 |
|
211 |
+ def no_bulk_receive? |
|
212 |
+ self.class.no_bulk_receive? |
|
213 |
+ end |
|
214 |
+ |
|
211 | 215 |
def log(message, options = {}) |
212 | 216 |
AgentLog.log_for_agent(self, message, options) |
213 | 217 |
end |
@@ -350,6 +354,14 @@ class Agent < ActiveRecord::Base |
||
350 | 354 |
!!@can_dry_run |
351 | 355 |
end |
352 | 356 |
|
357 |
+ def no_bulk_receive! |
|
358 |
+ @no_bulk_receive = true |
|
359 |
+ end |
|
360 |
+ |
|
361 |
+ def no_bulk_receive? |
|
362 |
+ !!@no_bulk_receive |
|
363 |
+ end |
|
364 |
+ |
|
353 | 365 |
def gem_dependency_check |
354 | 366 |
@gem_dependencies_checked = true |
355 | 367 |
@gem_dependencies_met = yield |
@@ -365,7 +377,7 @@ class Agent < ActiveRecord::Base |
||
365 | 377 |
def receive!(options={}) |
366 | 378 |
Agent.transaction do |
367 | 379 |
scope = Agent. |
368 |
- select("agents.id AS receiver_agent_id, sources.id AS source_agent_id, events.id AS event_id"). |
|
380 |
+ select("agents.id AS receiver_agent_id, events.id AS event_id"). |
|
369 | 381 |
joins("JOIN links ON (links.receiver_id = agents.id)"). |
370 | 382 |
joins("JOIN agents AS sources ON (links.source_id = sources.id)"). |
371 | 383 |
joins("JOIN events ON (events.agent_id = sources.id AND events.id > links.event_id_at_creation)"). |
@@ -377,21 +389,25 @@ class Agent < ActiveRecord::Base |
||
377 | 389 |
sql = scope.to_sql() |
378 | 390 |
|
379 | 391 |
agents_to_events = {} |
380 |
- Agent.connection.select_rows(sql).each do |receiver_agent_id, source_agent_id, event_id| |
|
392 |
+ Agent.connection.select_rows(sql).each do |receiver_agent_id, event_id| |
|
381 | 393 |
agents_to_events[receiver_agent_id.to_i] ||= [] |
382 | 394 |
agents_to_events[receiver_agent_id.to_i] << event_id |
383 | 395 |
end |
384 | 396 |
|
385 |
- event_ids = agents_to_events.values.flatten.uniq.compact |
|
386 |
- |
|
387 | 397 |
Agent.where(:id => agents_to_events.keys).each do |agent| |
398 |
+ event_ids = agents_to_events[agent.id].uniq |
|
388 | 399 |
agent.update_attribute :last_checked_event_id, event_ids.max |
389 |
- Agent.async_receive(agent.id, agents_to_events[agent.id].uniq) |
|
400 |
+ |
|
401 |
+ if agent.no_bulk_receive? |
|
402 |
+ event_ids.each { |event_id| Agent.async_receive(agent.id, [event_id]) } |
|
403 |
+ else |
|
404 |
+ Agent.async_receive(agent.id, event_ids) |
|
405 |
+ end |
|
390 | 406 |
end |
391 | 407 |
|
392 | 408 |
{ |
393 | 409 |
:agent_count => agents_to_events.keys.length, |
394 |
- :event_count => event_ids.length |
|
410 |
+ :event_count => agents_to_events.values.flatten.uniq.compact.length |
|
395 | 411 |
} |
396 | 412 |
end |
397 | 413 |
end |
@@ -2,6 +2,7 @@ module Agents |
||
2 | 2 |
class BeeperAgent < Agent |
3 | 3 |
cannot_be_scheduled! |
4 | 4 |
cannot_create_events! |
5 |
+ no_bulk_receive! |
|
5 | 6 |
|
6 | 7 |
description <<-MD |
7 | 8 |
Beeper agent sends messages to Beeper app on your mobile device via Push notifications. |
@@ -3,6 +3,7 @@ module Agents |
||
3 | 3 |
include DropboxConcern |
4 | 4 |
|
5 | 5 |
cannot_be_scheduled! |
6 |
+ no_bulk_receive! |
|
6 | 7 |
|
7 | 8 |
description <<-MD |
8 | 9 |
The Dropbox File Url Agent is used to work with Dropbox. It takes a file path (or multiple file paths) and emits events with [temporary links](https://www.dropbox.com/developers/core/docs#media). |
@@ -4,6 +4,7 @@ module Agents |
||
4 | 4 |
|
5 | 5 |
cannot_be_scheduled! |
6 | 6 |
cannot_create_events! |
7 |
+ no_bulk_receive! |
|
7 | 8 |
|
8 | 9 |
description <<-MD |
9 | 10 |
The Email Agent sends any events it receives via email immediately. |
@@ -3,6 +3,7 @@ require 'json' |
||
3 | 3 |
module Agents |
4 | 4 |
class GoogleCalendarPublishAgent < Agent |
5 | 5 |
cannot_be_scheduled! |
6 |
+ no_bulk_receive! |
|
6 | 7 |
|
7 | 8 |
gem_dependency_check { defined?(Google) && defined?(Google::APIClient) } |
8 | 9 |
|
@@ -4,6 +4,7 @@ module Agents |
||
4 | 4 |
|
5 | 5 |
cannot_be_scheduled! |
6 | 6 |
cannot_create_events! |
7 |
+ no_bulk_receive! |
|
7 | 8 |
|
8 | 9 |
gem_dependency_check { defined?(HipChat) } |
9 | 10 |
|
@@ -7,6 +7,7 @@ module Agents |
||
7 | 7 |
gem_dependency_check { defined?(HyPDF) } |
8 | 8 |
|
9 | 9 |
cannot_be_scheduled! |
10 |
+ no_bulk_receive! |
|
10 | 11 |
|
11 | 12 |
description <<-MD |
12 | 13 |
The PDF Info Agent returns the metadata contained within a given PDF file, using HyPDF. |
@@ -3,6 +3,7 @@ module Agents |
||
3 | 3 |
include WebRequestConcern |
4 | 4 |
|
5 | 5 |
can_dry_run! |
6 |
+ no_bulk_receive! |
|
6 | 7 |
default_schedule "never" |
7 | 8 |
|
8 | 9 |
description <<-MD |
@@ -4,6 +4,7 @@ module Agents |
||
4 | 4 |
|
5 | 5 |
cannot_be_scheduled! |
6 | 6 |
cannot_create_events! |
7 |
+ no_bulk_receive! |
|
7 | 8 |
|
8 | 9 |
before_validation :create_device, on: :create |
9 | 10 |
|
@@ -2,6 +2,8 @@ module Agents |
||
2 | 2 |
class PushoverAgent < Agent |
3 | 3 |
cannot_be_scheduled! |
4 | 4 |
cannot_create_events! |
5 |
+ no_bulk_receive! |
|
6 |
+ |
|
5 | 7 |
|
6 | 8 |
API_URL = 'https://api.pushover.net/1/messages.json' |
7 | 9 |
|
@@ -3,6 +3,8 @@ module Agents |
||
3 | 3 |
default_schedule "never" |
4 | 4 |
|
5 | 5 |
can_dry_run! |
6 |
+ no_bulk_receive! |
|
7 |
+ |
|
6 | 8 |
|
7 | 9 |
def self.should_run? |
8 | 10 |
ENV['ENABLE_INSECURE_AGENTS'] == "true" |
@@ -5,6 +5,7 @@ module Agents |
||
5 | 5 |
|
6 | 6 |
cannot_be_scheduled! |
7 | 7 |
cannot_create_events! |
8 |
+ no_bulk_receive! |
|
8 | 9 |
|
9 | 10 |
gem_dependency_check { defined?(Slack) } |
10 | 11 |
|
@@ -4,6 +4,7 @@ module Agents |
||
4 | 4 |
class TwilioAgent < Agent |
5 | 5 |
cannot_be_scheduled! |
6 | 6 |
cannot_create_events! |
7 |
+ no_bulk_receive! |
|
7 | 8 |
|
8 | 9 |
gem_dependency_check { defined?(Twilio) } |
9 | 10 |
|
@@ -7,6 +7,7 @@ module Agents |
||
7 | 7 |
|
8 | 8 |
can_dry_run! |
9 | 9 |
can_order_created_events! |
10 |
+ no_bulk_receive! |
|
10 | 11 |
|
11 | 12 |
default_schedule "every_12h" |
12 | 13 |
|
@@ -1,6 +1,7 @@ |
||
1 | 1 |
module Agents |
2 | 2 |
class WitaiAgent < Agent |
3 | 3 |
cannot_be_scheduled! |
4 |
+ no_bulk_receive! |
|
4 | 5 |
|
5 | 6 |
description <<-MD |
6 | 7 |
The `wit.ai` agent receives events, sends a text query to your `wit.ai` instance and generates outcome events. |
@@ -5,6 +5,7 @@ module Agents |
||
5 | 5 |
valid_oauth_providers :wunderlist |
6 | 6 |
|
7 | 7 |
cannot_be_scheduled! |
8 |
+ no_bulk_receive! |
|
8 | 9 |
|
9 | 10 |
gem_dependency_check { Devise.omniauth_providers.include?(:wunderlist) } |
10 | 11 |
|
@@ -56,7 +56,7 @@ describe HuginnScheduler do |
||
56 | 56 |
end |
57 | 57 |
end |
58 | 58 |
|
59 |
- describe "cleanup_failed_jobs!", focus: true do |
|
59 |
+ describe "cleanup_failed_jobs!" do |
|
60 | 60 |
before do |
61 | 61 |
3.times do |i| |
62 | 62 |
Delayed::Job.create(failed_at: Time.now - i.minutes) |
@@ -64,7 +64,7 @@ describe HuginnScheduler do |
||
64 | 64 |
@keep = Delayed::Job.order(:failed_at)[1] |
65 | 65 |
end |
66 | 66 |
|
67 |
- it "work with set FAILED_JOBS_TO_KEEP env variable", focus: true do |
|
67 |
+ it "work with set FAILED_JOBS_TO_KEEP env variable" do |
|
68 | 68 |
expect { @scheduler.send(:cleanup_failed_jobs!) }.to change(Delayed::Job, :count).by(-1) |
69 | 69 |
expect { @scheduler.send(:cleanup_failed_jobs!) }.to change(Delayed::Job, :count).by(0) |
70 | 70 |
expect(@keep.id).to eq(Delayed::Job.order(:failed_at)[0].id) |
@@ -295,6 +295,14 @@ describe Agent do |
||
295 | 295 |
Agent.receive! |
296 | 296 |
end |
297 | 297 |
|
298 |
+ it "should call receive for each event when no_bulk_receive! is used" do |
|
299 |
+ mock.any_instance_of(Agents::TriggerAgent).receive(anything).twice |
|
300 |
+ stub(Agents::TriggerAgent).no_bulk_receive? { true } |
|
301 |
+ Agent.async_check(agents(:bob_weather_agent).id) |
|
302 |
+ Agent.async_check(agents(:bob_weather_agent).id) |
|
303 |
+ Agent.receive! |
|
304 |
+ end |
|
305 |
+ |
|
298 | 306 |
it "should ignore events that were created before a particular Link" do |
299 | 307 |
agent2 = Agents::SomethingSource.new(:name => "something") |
300 | 308 |
agent2.user = users(:bob) |
@@ -50,6 +50,13 @@ RSpec.configure do |config| |
||
50 | 50 |
# rspec-rails. |
51 | 51 |
config.infer_base_class_for_anonymous_controllers = false |
52 | 52 |
|
53 |
+ # These two settings work together to allow you to limit a spec run |
|
54 |
+ # to individual examples or groups you care about by tagging them with |
|
55 |
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples |
|
56 |
+ # get run. |
|
57 |
+ config.filter_run :focus |
|
58 |
+ config.run_all_when_everything_filtered = true |
|
59 |
+ |
|
53 | 60 |
# Run specs in random order to surface order dependencies. If you find an |
54 | 61 |
# order dependency and want to debug it, you can fix the order by providing |
55 | 62 |
# the seed, which is printed after each run. |
@@ -30,7 +30,7 @@ shared_examples_for LiquidInterpolatable do |
||
30 | 30 |
}) |
31 | 31 |
end |
32 | 32 |
|
33 |
- it "should work with arrays", focus: true do |
|
33 |
+ it "should work with arrays" do |
|
34 | 34 |
@checker.options = {"value" => ["{{variable}}", "Much array", "Hey, {{hello_world}}"]} |
35 | 35 |
expect(@checker.interpolate_options(@checker.options, @event)).to eq({ |
36 | 36 |
"value" => ["hello", "Much array", "Hey, Hello world"] |