Skip to content
This repository
Browse code

Allow event stream delay to be overridden.

By default there is a five-second delay when event streaming, to give events
time to arrive before they are skipped by listeners. You can now change the
stream delay as part of the /event/get request. This is useful if there is a lag
for incoming events (say because of polling a primary data source), or if you
want a time-shifted stream of old events (say, those from yesterday).
  • Loading branch information...
commit e51cd376c36325aacd83c7b4e42894b1be80a429 1 parent 614573e
Mike Bostock authored April 15, 2012
32  examples/event-stream/event-get.html
... ...
@@ -0,0 +1,32 @@
  1
+<!DOCTYPE html>
  2
+<meta charset="utf-8">
  3
+<h1>Streaming Events - Get</h1>
  4
+
  5
+<p>This page streams events from Cube's evaluator (the /event/get endpoint) and logs them to the JavaScript console. If you open <a href="event-put.html" target="_blank">event-put.html</a> in a new window, you'll start receiving events.
  6
+
  7
+<script>
  8
+
  9
+var socket = new WebSocket("ws://localhost:1081/1.0/event/get");
  10
+
  11
+socket.onopen = function() {
  12
+  console.log("connected!");
  13
+  socket.send(JSON.stringify({
  14
+    expression: "test(index)",
  15
+    start: new Date()
  16
+  }));
  17
+};
  18
+
  19
+socket.onmessage = function(message) {
  20
+  var event = JSON.parse(message.data);
  21
+  console.log("received", event.data.index);
  22
+};
  23
+
  24
+socket.onclose = function() {
  25
+  console.log("closed");
  26
+};
  27
+
  28
+socket.onerror = function(error) {
  29
+  console.log("error", error);
  30
+};
  31
+
  32
+</script>
38  examples/event-stream/event-put.html
... ...
@@ -0,0 +1,38 @@
  1
+<!DOCTYPE html>
  2
+<meta charset="utf-8">
  3
+<h1>Streaming Events - Put</h1>
  4
+
  5
+<p>This page streams events to Cube's collector (the /event/put endpoint) and logs them to the JavaScript console. If you open <a href="event-get.html" target="_blank">event-get.html</a> in a new window, you can verify that Cube is receiving the events.
  6
+
  7
+<script>
  8
+
  9
+var index = 0;
  10
+
  11
+var socket = new WebSocket("ws://localhost:1080/1.0/event/put");
  12
+
  13
+socket.onopen = function() {
  14
+  console.log("connected!");
  15
+  setInterval(function() {
  16
+    socket.send(JSON.stringify({
  17
+      type: "test",
  18
+      time: new Date(),
  19
+      data: {index: ++index}
  20
+    }));
  21
+    console.log("sent", index);
  22
+  }, 1000);
  23
+};
  24
+
  25
+socket.onmessage = function(message) {
  26
+  var event = JSON.parse(message.data);
  27
+  console.log("received", event);
  28
+};
  29
+
  30
+socket.onclose = function() {
  31
+  console.log("closed");
  32
+};
  33
+
  34
+socket.onerror = function(error) {
  35
+  console.log("error", error);
  36
+};
  37
+
  38
+</script>
30  lib/cube/server/event.js
@@ -13,6 +13,12 @@ var type_re = /^[a-z][a-zA-Z0-9_]+$/,
13 13
     event_options = {sort: {t: -1}, batchSize: 1000},
14 14
     metric_options = {capped: true, size: 1e7, autoIndexId: true};
15 15
 
  16
+// When streaming events, we should allow a delay for events to arrive, or else
  17
+// we risk skipping events that arrive after their event.time. This delay can be
  18
+// customized by specifying a `delay` property as part of the request.
  19
+var streamDelayDefault = 5000,
  20
+    streamInterval = 1000;
  21
+
16 22
 exports.putter = function(db) {
17 23
   var collection = types(db),
18 24
       knownByType = {},
@@ -91,13 +97,13 @@ exports.putter = function(db) {
91 97
 };
92 98
 
93 99
 exports.getter = function(db) {
94  
-  var collection = types(db),
95  
-      streamDelay = 5000;
  100
+  var collection = types(db);
96 101
 
97 102
   function getter(request, callback) {
98 103
     var stream = !("stop" in request),
  104
+        delay = "delay" in request ? +request.delay : streamDelayDefault,
99 105
         start = new Date(request.start),
100  
-        stop = stream ? new Date(Date.now() - streamDelay) : new Date(request.stop);
  106
+        stop = stream ? new Date(Date.now() - delay) : new Date(request.stop);
101 107
 
102 108
     // Validate the dates.
103 109
     if (isNaN(start)) return callback({error: "invalid start"}), -1;
@@ -134,24 +140,20 @@ exports.getter = function(db) {
134 140
           else handle(error);
135 141
 
136 142
           // A null event indicates that there are no more results. For
137  
-          // streaming queries, we don't report this sentinel value.
  143
+          // streaming queries, we don't report this sentinel value, and instead
  144
+          // set a timeout to issue another query for more recent results.
138 145
           if (event) callback({time: event.t, data: event.d});
139 146
           else if (!stream) callback(null);
  147
+          else {
  148
+            filter.t.$gte = stop;
  149
+            filter.t.$lt = stop = new Date(Date.now() - delay);
  150
+            setTimeout(query, streamInterval);
  151
+          }
140 152
         });
141 153
       });
142 154
     }
143 155
 
144 156
     query();
145  
-
146  
-    // While streaming, periodically poll for new results.
147  
-    if (stream) {
148  
-      stream = setInterval(function() {
149  
-        if (callback.closed) return clearInterval(stream);
150  
-        filter.t.$gte = stop;
151  
-        filter.t.$lt = stop = new Date(Date.now() - streamDelay);
152  
-        query();
153  
-      }, streamDelay);
154  
-    }
155 157
   }
156 158
 
157 159
   getter.close = function(callback) {

0 notes on commit e51cd37

Please sign in to comment.
Something went wrong with that request. Please try again.