first working version of Agents that propagate immediately

qedi 10 years ago
parent
commit
31e4d152cc

+ 2 - 0
app/assets/javascripts/application.js.coffee.erb

@@ -27,10 +27,12 @@ showSchedule = ->
27 27
 
28 28
 hideLinks = ->
29 29
   $(".link-region .select2-container").hide()
30
+  $(".link-region .propagate-immediately").hide()
30 31
   $(".link-region .cannot-receive-events").show()
31 32
 
32 33
 showLinks = ->
33 34
   $(".link-region .select2-container").show()
35
+  $(".link-region .propagate-immediately").show()
34 36
   $(".link-region .cannot-receive-events").hide()
35 37
   showEventDescriptions()
36 38
 

+ 14 - 5
app/models/agent.rb

@@ -20,7 +20,7 @@ class Agent < ActiveRecord::Base
20 20
 
21 21
   EVENT_RETENTION_SCHEDULES = [["Forever", 0], ["1 day", 1], *([2, 3, 4, 5, 7, 14, 21, 30, 45, 90, 180, 365].map {|n| ["#{n} days", n] })]
22 22
 
23
-  attr_accessible :options, :memory, :name, :type, :schedule, :source_ids, :keep_events_for
23
+  attr_accessible :options, :memory, :name, :type, :schedule, :source_ids, :keep_events_for, :propagate_immediately
24 24
 
25 25
   json_serialize :options, :memory
26 26
 
@@ -96,7 +96,11 @@ class Agent < ActiveRecord::Base
96 96
 
97 97
   def create_event(attrs)
98 98
     if can_create_events?
99
-      events.create!({ :user => user, :expires_at => new_event_expiration_date }.merge(attrs))
99
+      events.create!({ 
100
+         :user => user, 
101
+         :expires_at => new_event_expiration_date, 
102
+         :propagate_immediately => propagate_immediately
103
+      }.merge(attrs))
100 104
     else
101 105
       error "This Agent cannot create events!"
102 106
     end
@@ -246,14 +250,19 @@ class Agent < ActiveRecord::Base
246 250
     # Find all Agents that have received Events since the last execution of this method.  Update those Agents with
247 251
     # their new `last_checked_event_id` and queue each of the Agents to be called with #receive using `async_receive`.
248 252
     # This is called by bin/schedule.rb periodically.
249
-    def receive!
253
+    def receive!(options={})
250 254
       Agent.transaction do
251
-        sql = Agent.
255
+        scope = Agent.
252 256
                 select("agents.id AS receiver_agent_id, sources.id AS source_agent_id, events.id AS event_id").
253 257
                 joins("JOIN links ON (links.receiver_id = agents.id)").
254 258
                 joins("JOIN agents AS sources ON (links.source_id = sources.id)").
255 259
                 joins("JOIN events ON (events.agent_id = sources.id AND events.id > links.event_id_at_creation)").
256
-                where("agents.last_checked_event_id IS NULL OR events.id > agents.last_checked_event_id").to_sql
260
+                where("agents.last_checked_event_id IS NULL OR events.id > agents.last_checked_event_id")
261
+        if options[:only_receivers].present?
262
+          scope = scope.where("agents.id in (?)", options[:only_receivers])
263
+        end
264
+ 
265
+        sql = scope.to_sql()
257 266
 
258 267
         agents_to_events = {}
259 268
         Agent.connection.select_rows(sql).each do |receiver_agent_id, source_agent_id, event_id|

+ 11 - 1
app/models/event.rb

@@ -6,7 +6,8 @@ require 'json_serialized_field'
6 6
 class Event < ActiveRecord::Base
7 7
   include JSONSerializedField
8 8
 
9
-  attr_accessible :lat, :lng, :payload, :user_id, :user, :expires_at
9
+  attr_accessor :propagate_immediately
10
+  attr_accessible :lat, :lng, :payload, :user_id, :user, :expires_at, :propagate_immediately
10 11
 
11 12
   acts_as_mappable
12 13
 
@@ -19,6 +20,8 @@ class Event < ActiveRecord::Base
19 20
     where("events.created_at > ?", timespan)
20 21
   }
21 22
 
23
+  after_create :possibly_propagate
24
+
22 25
   # Emit this event again, as a new Event.
23 26
   def reemit!
24 27
     agent.create_event :payload => payload, :lat => lat, :lng => lng
@@ -31,4 +34,11 @@ class Event < ActiveRecord::Base
31 34
     Event.where("expires_at IS NOT NULL AND expires_at < ?", Time.now).delete_all
32 35
     Agent.where(:id => affected_agents).update_all "events_count = (select count(*) from events where agent_id = agents.id)"
33 36
   end
37
+
38
+  protected
39
+  def possibly_propagate
40
+    #immediately schedule agents that want immediate updates
41
+    propagate_ids = agent.receivers.where(:propagate_immediately => true).pluck(:id)
42
+    Agent.receive!(:only_receivers => propagate_ids) unless propagate_ids.empty?
43
+  end
34 44
 end

+ 1 - 1
app/views/agents/_form.html.erb

@@ -42,7 +42,6 @@
42 42
       <%= f.select :schedule, options_for_select(Agent::SCHEDULES.map {|s| [s.humanize.titleize, s] }, @agent.schedule), {}, :class => 'span4' %>
43 43
       <span class='cannot-be-scheduled text-info'>This type of Agent cannot be scheduled.</span>
44 44
     </div>
45
-  </div>
46 45
 
47 46
   <div class='event-related-region' data-can-create-events="<%= @agent.can_create_events? %>">
48 47
     <div class="control-group">
@@ -62,6 +61,7 @@
62 61
                                       @agent.source_ids),
63 62
                    {}, { :multiple => true, :size => 5, :class => 'span4 select2' }) %>
64 63
       <span class='cannot-receive-events text-info'>This type of Agent cannot receive events.</span>
64
+      <span class="propagate-immediately"><br><%= f.check_box :propagate_immediately %> <%= f.label "Propagate immediately", :class => 'control-label' %></span>
65 65
     </div>
66 66
   </div>
67 67
 

+ 10 - 0
db/migrate/20140216201250_add_propagate_immediately_to_agent.rb

@@ -0,0 +1,10 @@
1
+class AddPropagateImmediatelyToAgent < ActiveRecord::Migration
2
+  def up
3
+    add_column :agents, :propagate_immediately, :boolean, :default => false, :null => false
4
+    execute "UPDATE agents SET propagate_immediately = 0"
5
+  end
6
+
7
+  def down
8
+    remove_column :agents, :propagate_immediately
9
+  end
10
+end

+ 17 - 24
db/schema.rb

@@ -11,21 +11,21 @@
11 11
 #
12 12
 # It's strongly recommended to check this file into your version control system.
13 13
 
14
-ActiveRecord::Schema.define(:version => 20140213053001) do
14
+ActiveRecord::Schema.define(:version => 20140216201250) do
15 15
 
16 16
   create_table "agent_logs", :force => true do |t|
17
-    t.integer  "agent_id",                                             :null => false
18
-    t.text     "message",           :limit => 16777215,                :null => false
19
-    t.integer  "level",                                 :default => 3, :null => false
17
+    t.integer  "agent_id",                         :null => false
18
+    t.text     "message",                          :null => false
19
+    t.integer  "level",             :default => 3, :null => false
20 20
     t.integer  "inbound_event_id"
21 21
     t.integer  "outbound_event_id"
22
-    t.datetime "created_at",                                           :null => false
23
-    t.datetime "updated_at",                                           :null => false
22
+    t.datetime "created_at",                       :null => false
23
+    t.datetime "updated_at",                       :null => false
24 24
   end
25 25
 
26 26
   create_table "agents", :force => true do |t|
27 27
     t.integer  "user_id"
28
-    t.text     "options",               :limit => 16777215
28
+    t.text     "options"
29 29
     t.string   "type"
30 30
     t.string   "name"
31 31
     t.string   "schedule"
@@ -33,32 +33,25 @@ ActiveRecord::Schema.define(:version => 20140213053001) do
33 33
     t.datetime "last_check_at"
34 34
     t.datetime "last_receive_at"
35 35
     t.integer  "last_checked_event_id"
36
-    t.datetime "created_at",                                                 :null => false
37
-    t.datetime "updated_at",                                                 :null => false
36
+    t.datetime "created_at",                                                     :null => false
37
+    t.datetime "updated_at",                                                     :null => false
38 38
     t.text     "memory",                :limit => 2147483647
39 39
     t.datetime "last_webhook_at"
40
+    t.integer  "keep_events_for",                             :default => 0,     :null => false
40 41
     t.datetime "last_event_at"
41 42
     t.datetime "last_error_log_at"
42
-    t.integer  "keep_events_for",                             :default => 0, :null => false
43
+    t.boolean  "propagate_immediately",                       :default => false, :null => false
43 44
   end
44 45
 
45 46
   add_index "agents", ["schedule"], :name => "index_agents_on_schedule"
46 47
   add_index "agents", ["type"], :name => "index_agents_on_type"
47 48
   add_index "agents", ["user_id", "created_at"], :name => "index_agents_on_user_id_and_created_at"
48 49
 
49
-  create_table "contacts", :force => true do |t|
50
-    t.text     "message"
51
-    t.string   "name"
52
-    t.string   "email"
53
-    t.datetime "created_at", :null => false
54
-    t.datetime "updated_at", :null => false
55
-  end
56
-
57 50
   create_table "delayed_jobs", :force => true do |t|
58 51
     t.integer  "priority",                       :default => 0
59 52
     t.integer  "attempts",                       :default => 0
60 53
     t.text     "handler",    :limit => 16777215
61
-    t.text     "last_error", :limit => 16777215
54
+    t.text     "last_error"
62 55
     t.datetime "run_at"
63 56
     t.datetime "locked_at"
64 57
     t.datetime "failed_at"
@@ -73,11 +66,11 @@ ActiveRecord::Schema.define(:version => 20140213053001) do
73 66
   create_table "events", :force => true do |t|
74 67
     t.integer  "user_id"
75 68
     t.integer  "agent_id"
76
-    t.decimal  "lat",                              :precision => 15, :scale => 10
77
-    t.decimal  "lng",                              :precision => 15, :scale => 10
78
-    t.text     "payload",    :limit => 2147483647
79
-    t.datetime "created_at",                                                       :null => false
80
-    t.datetime "updated_at",                                                       :null => false
69
+    t.decimal  "lat",                            :precision => 15, :scale => 10
70
+    t.decimal  "lng",                            :precision => 15, :scale => 10
71
+    t.text     "payload",    :limit => 16777215
72
+    t.datetime "created_at",                                                     :null => false
73
+    t.datetime "updated_at",                                                     :null => false
81 74
     t.datetime "expires_at"
82 75
   end
83 76
 

+ 55 - 0
spec/models/agent_spec.rb

@@ -302,6 +302,61 @@ describe Agent do
302 302
       end
303 303
     end
304 304
 
305
+    describe "creating agents with propagate_immediately = true" do
306
+      it "should schedule subagent events immediately" do
307
+        Event.delete_all
308
+        sender = Agents::SomethingSource.new(:name => "Sending Agent")
309
+        sender.user = users(:bob)
310
+        sender.save!
311
+
312
+        receiver = Agents::CannotBeScheduled.new(
313
+           :name => "Receiving Agent",
314
+        )
315
+        receiver.propagate_immediately = true
316
+        receiver.user = users(:bob)
317
+        receiver.sources << sender
318
+        receiver.save!
319
+
320
+        sender.create_event :payload => {"message" => "new payload"}
321
+        sender.events.count.should == 1
322
+        receiver.events.count.should == 1
323
+        #should be true without calling Agent.receive!
324
+      end
325
+
326
+      it "should only schedule receiving agents that are set to propagate_immediately" do
327
+        Event.delete_all
328
+        sender = Agents::SomethingSource.new(:name => "Sending Agent")
329
+        sender.user = users(:bob)
330
+        sender.save!
331
+
332
+        im_receiver = Agents::CannotBeScheduled.new(
333
+           :name => "Immediate Receiving Agent",
334
+        )
335
+        im_receiver.propagate_immediately = true
336
+        im_receiver.user = users(:bob)
337
+        im_receiver.sources << sender
338
+
339
+        im_receiver.save!
340
+        slow_receiver = Agents::CannotBeScheduled.new(
341
+           :name => "Slow Receiving Agent",
342
+        )
343
+        slow_receiver.user = users(:bob)
344
+        slow_receiver.sources << sender
345
+        slow_receiver.save!
346
+
347
+        sender.create_event :payload => {"message" => "new payload"}
348
+        sender.events.count.should == 1
349
+        im_receiver.events.count.should == 1
350
+        #we should get the quick one
351
+        #but not the slow one
352
+        slow_receiver.events.count.should == 0
353
+        Agent.receive!
354
+        #now we should have one in both
355
+        im_receiver.events.count.should == 1
356
+        slow_receiver.events.count.should == 1
357
+      end
358
+    end
359
+
305 360
     describe "validations" do
306 361
       it "calls validate_options" do
307 362
         agent = Agents::SomethingSource.new(:name => "something")