durable_rules 0.33.13 → 0.34.01

Sign up to get free protection for your applications and to get access to all the features.
data/librb/engine.rb CHANGED
@@ -3,20 +3,25 @@ require "timers"
3
3
  require_relative "../src/rulesrb/rules"
4
4
 
5
5
  module Engine
6
-
6
+ @@timers = nil
7
7
  class Closure
8
- attr_reader :handle, :ruleset_name, :_timers, :_branches, :_messages, :_facts, :_retract
8
+ attr_reader :host, :handle, :ruleset_name, :_timers, :_cancelled_timers, :_branches, :_messages, :_queued_messages, :_facts, :_retract
9
9
  attr_accessor :s
10
10
 
11
- def initialize(state, message, handle, ruleset_name)
11
+ def initialize(host, state, message, handle, ruleset_name)
12
12
  @s = Content.new(state)
13
13
  @ruleset_name = ruleset_name
14
14
  @handle = handle
15
+ @host = host
15
16
  @_timers = {}
17
+ @_cancelled_timers = {}
16
18
  @_messages = {}
19
+ @_queued_messages = {}
17
20
  @_branches = {}
18
21
  @_facts = {}
19
22
  @_retract = {}
23
+ @_start_time = Time.now
24
+ @_completed = false
20
25
  if message.kind_of? Hash
21
26
  @m = message
22
27
  else
@@ -53,11 +58,47 @@ module Engine
53
58
  message_list << message
54
59
  end
55
60
 
56
- def start_timer(timer_name, duration)
57
- if @_timers.key? timer_name
58
- raise ArgumentError, "Timer with name #{timer_name} already added"
61
+ def queue(ruleset_name, message)
62
+ if message.kind_of? Content
63
+ message = message._d
64
+ end
65
+
66
+ if !(message.key? :sid) && !(message.key? "sid")
67
+ message[:sid] = @s.sid
68
+ end
69
+
70
+ message_list = []
71
+ if @_queued_messages.key? ruleset_name
72
+ message_list = @_queued_messages[ruleset_name]
59
73
  else
60
- @_timers[timer_name] = duration
74
+ @_queued_messages[ruleset_name] = message_list
75
+ end
76
+ message_list << message
77
+ end
78
+
79
+ def start_timer(timer_name, duration, timer_id = nil)
80
+ if !timer_id
81
+ timer_id = timer_name
82
+ end
83
+
84
+ if @_timers.key? timer_id
85
+ raise ArgumentError, "Timer with id #{timer_id} already added"
86
+ else
87
+ timer = {:sid => @s.sid, :id => timer_id, :$t => timer_name}
88
+ @_timers[timer_id] = [timer, duration]
89
+ end
90
+ end
91
+
92
+ def cancel_timer(timer_name, timer_id = nil)
93
+ if !timer_id
94
+ timer_id = timer_name
95
+ end
96
+
97
+ if @_cancelled_timers.key? timer_id
98
+ raise ArgumentError, "Timer with id #{timer_id} already cancelled"
99
+ else
100
+ timer = {:sid => @s.sid, :id => timer_id, :$t => timer_name}
101
+ @_cancelled_timers[timer_id] = timer
61
102
  end
62
103
  end
63
104
 
@@ -107,6 +148,22 @@ module Engine
107
148
  fact_list << fact
108
149
  end
109
150
 
151
+ def renew_action_lease()
152
+ if Time.now - @_start_time < 10000
153
+ @_start_time = Time.now
154
+ @host.renew_action_lease(@ruleset_name, @s.sid)
155
+ end
156
+ end
157
+
158
+ def has_completed()
159
+ if Time.now - @_start_time > 10000
160
+ @_completed = true
161
+ end
162
+ value = @_completed
163
+ @_completed = true
164
+ value
165
+ end
166
+
110
167
  private
111
168
 
112
169
  def handle_property(name, value=nil)
@@ -146,7 +203,11 @@ module Engine
146
203
  def handle_property(name, value=nil)
147
204
  name = name.to_s
148
205
  if name.end_with? '='
149
- @_d[name[0..-2]] = value
206
+ if value == nil
207
+ @_d.delete(name[0..-2])
208
+ else
209
+ @_d[name[0..-2]] = value
210
+ end
150
211
  nil
151
212
  elsif name.end_with? '?'
152
213
  @_d.key? name[0..-2]
@@ -167,12 +228,16 @@ module Engine
167
228
 
168
229
  class Promise
169
230
  attr_accessor :root
170
-
171
231
  def initialize(func)
172
232
  @func = func
173
233
  @next = nil
174
234
  @sync = true
175
235
  @root = self
236
+ @timers = Timers::Group.new
237
+
238
+ if func.arity > 1
239
+ @sync = false
240
+ end
176
241
  end
177
242
 
178
243
  def continue_with(next_func)
@@ -193,8 +258,9 @@ module Engine
193
258
  begin
194
259
  @func.call c
195
260
  rescue Exception => e
196
- complete.call e
197
- return
261
+ puts "unexpected error #{e}"
262
+ puts e.backtrace
263
+ c.s.exception = e.to_s
198
264
  end
199
265
 
200
266
  if @next
@@ -204,17 +270,37 @@ module Engine
204
270
  end
205
271
  else
206
272
  begin
207
- @func.call c, -> e {
273
+ time_left = @func.call c, -> e {
208
274
  if e
209
- complete.call e
275
+ c.s.exception = e.to_s
276
+ complete.call nil
210
277
  elsif @next
211
278
  @next.run c, complete
212
279
  else
213
280
  complete.call nil
214
281
  end
215
282
  }
283
+
284
+ if time_left && (time_left.kind_of? Integer)
285
+ max_time = Time.now + time_left
286
+ my_timer = @timers.every(5) {
287
+ if Time.now > max_time
288
+ my_timer.cancel
289
+ c.s.exception = "timeout expired"
290
+ complete.call nil
291
+ else
292
+ c.renew_action_lease()
293
+ end
294
+ }
295
+ Thread.new do
296
+ loop { @timers.wait }
297
+ end
298
+ end
216
299
  rescue Exception => e
217
- complete.call e
300
+ puts "unexpected error #{e}"
301
+ puts e.backtrace
302
+ c.s.exception = e.to_s
303
+ complete.call nil
218
304
  end
219
305
  end
220
306
  end
@@ -296,6 +382,10 @@ module Engine
296
382
  Rules.assert_event @handle, JSON.generate(message)
297
383
  end
298
384
 
385
+ def queue_event(sid, ruleset_name, message)
386
+ Rules.queue_event @handle, sid.to_s, ruleset_name.to_s, JSON.generate(message)
387
+ end
388
+
299
389
  def start_assert_event(message)
300
390
  return Rules.start_assert_event @handle, JSON.generate(message)
301
391
  end
@@ -308,11 +398,14 @@ module Engine
308
398
  return Rules.start_assert_events @handle, JSON.generate(messages)
309
399
  end
310
400
 
311
- def start_timer(sid, timer_name, timer_duration)
312
- timer = {:sid => sid, :id => rand(1000000000), :$t => timer_name}
401
+ def start_timer(sid, timer, timer_duration)
313
402
  Rules.start_timer @handle, sid.to_s, timer_duration, JSON.generate(timer)
314
403
  end
315
404
 
405
+ def cancel_timer(sid, timer)
406
+ Rules.cancel_timer @handle, sid.to_s, JSON.generate(timer)
407
+ end
408
+
316
409
  def assert_fact(fact)
317
410
  Rules.assert_fact @handle, JSON.generate(fact)
318
411
  end
@@ -350,9 +443,13 @@ module Engine
350
443
  end
351
444
 
352
445
  def get_state(sid)
353
- JSON.parse Rules.get_state(@handle, sid)
446
+ JSON.parse Rules.get_state(@handle, sid.to_s)
354
447
  end
355
448
 
449
+ def renew_action_lease(sid)
450
+ Rules.renew_action_lease @handle, sid.to_s
451
+ end
452
+
356
453
  def Ruleset.create_rulesets(parent_name, host, ruleset_definitions, state_cache_size)
357
454
  branches = {}
358
455
  for name, definition in ruleset_definitions do
@@ -385,22 +482,29 @@ module Engine
385
482
  complete.call nil
386
483
  end
387
484
 
388
- def dispatch(complete)
485
+ def dispatch(complete, async_result = nil)
389
486
  result_container = {}
390
487
  action_handle = nil
391
488
  action_binding = nil
392
489
  state = nil
393
- begin
394
- result = Rules.start_action @handle
395
- if result
396
- state = JSON.parse result[0]
397
- result_container = {:message => JSON.parse(result[1])}
398
- action_handle = result[2]
399
- action_binding = result[3]
490
+ if async_result
491
+ state = async_result[0]
492
+ result_container = {:message => JSON.parse(async_result[1])}
493
+ action_handle = async_result[2]
494
+ action_binding = async_result[3]
495
+ else
496
+ begin
497
+ result = Rules.start_action @handle
498
+ if result
499
+ state = JSON.parse result[0]
500
+ result_container = {:message => JSON.parse(result[1])}
501
+ action_handle = result[2]
502
+ action_binding = result[3]
503
+ end
504
+ rescue Exception => e
505
+ complete.call e
506
+ return
400
507
  end
401
- rescue Exception => e
402
- complete.call e
403
- return
404
508
  end
405
509
 
406
510
  while result_container.key? :message do
@@ -410,16 +514,36 @@ module Engine
410
514
  end
411
515
 
412
516
  result_container.delete :message
413
- c = Closure.new state, message, action_handle, @name
517
+ c = Closure.new @host, state, message, action_handle, @name
518
+
519
+ if result_container.key? :async
520
+ result_container.delete :async
521
+ end
522
+
414
523
  @actions[action_name].run c, -> e {
524
+ if c.has_completed
525
+ return
526
+ end
527
+
415
528
  if e
416
529
  Rules.abandon_action @handle, c.handle
417
530
  complete.call e
418
531
  else
419
532
  begin
420
- for timer_name, timer_duration in c._timers do
421
- start_timer c.s.sid, timer_name, timer_duration
533
+ for timer_id, timer in c._cancelled_timers do
534
+ cancel_timer c.s.sid, timer
535
+ end
536
+
537
+ for timer_id, timer_duration in c._timers do
538
+ start_timer c.s.sid, timer_duration[0], timer_duration[1]
422
539
  end
540
+
541
+ for ruleset_name, messages in c._queued_messages do
542
+ for message in messages do
543
+ queue_event c.s.sid, ruleset_name, message
544
+ end
545
+ end
546
+
423
547
  binding = 0
424
548
  replies = 0
425
549
  pending = {action_binding => 0}
@@ -465,6 +589,7 @@ module Engine
465
589
  else
466
590
  pending[binding] = replies
467
591
  end
592
+
468
593
  for binding, replies in pending do
469
594
  if binding != 0
470
595
  if binding != action_binding
@@ -472,17 +597,24 @@ module Engine
472
597
  else
473
598
  new_result = Rules.complete_and_start_action @handle, replies, c.handle
474
599
  if new_result
475
- result_container[:message] = JSON.parse new_result
600
+ if result_container.key? :async
601
+ dispatch -> e {}, [state, new_result, action_handle, action_binding]
602
+ else
603
+ result_container[:message] = JSON.parse new_result
604
+ end
476
605
  end
477
606
  end
478
607
  end
479
608
  end
480
609
  rescue Exception => e
481
610
  Rules.abandon_action @handle, c.handle
611
+ puts "internal error #{e}"
612
+ puts e.backtrace
482
613
  complete.call e
483
614
  end
484
615
  end
485
616
  }
617
+ result_container[:async] = true
486
618
  end
487
619
  complete.call nil
488
620
  end
@@ -533,8 +665,7 @@ module Engine
533
665
  if parent_triggers
534
666
  for parent_trigger_name, trigger in parent_triggers do
535
667
  parent_trigger_name = parent_trigger_name.to_s
536
- trigger_name = parent_trigger_name[parent_trigger_name.rindex('.')..-1]
537
- triggers["#{qualified_name}.#{trigger_name}"] = trigger
668
+ triggers["#{qualified_name}.#{parent_trigger_name}"] = trigger
538
669
  end
539
670
  end
540
671
 
@@ -954,6 +1085,10 @@ module Engine
954
1085
  get_ruleset(ruleset_name).assert_state state
955
1086
  end
956
1087
 
1088
+ def renew_action_lease(ruleset_name, sid)
1089
+ get_ruleset(ruleset_name).renew_action_lease sid
1090
+ end
1091
+
957
1092
  def register_rulesets(parent_name, ruleset_definitions)
958
1093
  rulesets = Ruleset.create_rulesets(parent_name, self, ruleset_definitions, @state_cache_size)
959
1094
  for ruleset_name, ruleset in rulesets do
@@ -976,8 +1111,7 @@ module Engine
976
1111
  dispatch_ruleset = -> c {
977
1112
 
978
1113
  callback = -> e {
979
- puts "internal error #{e}" if e
980
- if index % 10 == 0
1114
+ if index % 5 == 0
981
1115
  index += 1
982
1116
  timers.after 0.01, &dispatch_ruleset
983
1117
  else
@@ -987,9 +1121,8 @@ module Engine
987
1121
  }
988
1122
 
989
1123
  timers_callback = -> e {
990
- puts "internal error #{e}" if e
991
- if index % 10 == 0 && @ruleset_list.length > 0
992
- ruleset = @ruleset_list[(index / 10) % @ruleset_list.length]
1124
+ if index % 5 == 0 && @ruleset_list.length > 0
1125
+ ruleset = @ruleset_list[(index / 5) % @ruleset_list.length]
993
1126
  ruleset.dispatch_timers callback
994
1127
  else
995
1128
  callback.call e
@@ -1004,7 +1137,7 @@ module Engine
1004
1137
  end
1005
1138
  }
1006
1139
 
1007
- timers.after 0.001, &dispatch_ruleset
1140
+ timers.after 0.01, &dispatch_ruleset
1008
1141
  Thread.new do
1009
1142
  loop { timers.wait }
1010
1143
  end
data/src/rules/events.c CHANGED
@@ -793,7 +793,7 @@ static unsigned int isMatch(ruleset *tree,
793
793
  *propertyMatch = compareDouble(currentProperty->value.i, rightProperty->value.i, alphaOp);
794
794
  break;
795
795
  case OP_DOUBLE_DOUBLE:
796
- *propertyMatch = compareDouble(currentProperty->value.i, rightProperty->value.d, alphaOp);
796
+ *propertyMatch = compareDouble(currentProperty->value.d, rightProperty->value.d, alphaOp);
797
797
  break;
798
798
  case OP_DOUBLE_STRING:
799
799
  {
@@ -869,7 +869,6 @@ static unsigned int isMatch(ruleset *tree,
869
869
  if (releaseRightState) {
870
870
  free(rightState);
871
871
  }
872
-
873
872
  return result;
874
873
  }
875
874
 
@@ -1439,7 +1438,6 @@ static unsigned int handleTimers(void *handle,
1439
1438
 
1440
1439
  commands[*commandCount] = command;
1441
1440
  ++*commandCount;
1442
-
1443
1441
  result = handleMessage(handle,
1444
1442
  NULL,
1445
1443
  reply->element[i]->str,
@@ -1711,6 +1709,10 @@ unsigned int startAction(void *handle,
1711
1709
  *state = reply->element[1]->str;
1712
1710
  *messages = reply->element[2]->str;
1713
1711
  actionContext *context = malloc(sizeof(actionContext));
1712
+ if (!context) {
1713
+ return ERR_OUT_OF_MEMORY;
1714
+ }
1715
+
1714
1716
  context->reply = reply;
1715
1717
  context->rulesBinding = rulesBinding;
1716
1718
  *actionHandle = context;
@@ -1771,7 +1773,12 @@ unsigned int completeAction(void *handle,
1771
1773
  return result;
1772
1774
  }
1773
1775
 
1774
- result = executeBatch(rulesBinding, commands, commandCount);
1776
+ result = executeBatch(rulesBinding, commands, commandCount);
1777
+ if (result != RULES_OK) {
1778
+ //reply object should be freed by the app during abandonAction
1779
+ return result;
1780
+ }
1781
+
1775
1782
  freeReplyObject(reply);
1776
1783
  free(actionHandle);
1777
1784
  return result;
@@ -1840,6 +1847,16 @@ unsigned int abandonAction(void *handle, void *actionHandle) {
1840
1847
  return RULES_OK;
1841
1848
  }
1842
1849
 
1850
+ unsigned int queueMessage(void *handle, char *sid, char *destination, char *message) {
1851
+ void *rulesBinding;
1852
+ unsigned int result = resolveBinding(handle, sid, &rulesBinding);
1853
+ if (result != RULES_OK) {
1854
+ return result;
1855
+ }
1856
+
1857
+ return registerMessage(rulesBinding, destination, message);
1858
+ }
1859
+
1843
1860
  unsigned int startTimer(void *handle, char *sid, unsigned int duration, char *timer) {
1844
1861
  void *rulesBinding;
1845
1862
  unsigned int result = resolveBinding(handle, sid, &rulesBinding);
@@ -1849,3 +1866,24 @@ unsigned int startTimer(void *handle, char *sid, unsigned int duration, char *ti
1849
1866
 
1850
1867
  return registerTimer(rulesBinding, duration, timer);
1851
1868
  }
1869
+
1870
+ unsigned int cancelTimer(void *handle, char *sid, char *timer) {
1871
+ void *rulesBinding;
1872
+ unsigned int result = resolveBinding(handle, sid, &rulesBinding);
1873
+ if (result != RULES_OK) {
1874
+ return result;
1875
+ }
1876
+
1877
+ return removeTimer(rulesBinding, timer);
1878
+ }
1879
+
1880
+ unsigned int renewActionLease(void *handle, char *sid) {
1881
+ void *rulesBinding;
1882
+ unsigned int result = resolveBinding(handle, sid, &rulesBinding);
1883
+ if (result != RULES_OK) {
1884
+ return result;
1885
+ }
1886
+
1887
+ return updateAction(rulesBinding, sid);
1888
+ }
1889
+