Skip to content

Commit ab713dd

Browse files
author
Zachary Crockett
committed
Merge pull request #7 from spark/feature/rate-limit-publish
Rate limit Spark.publish to 4 events per second
2 parents 63f9421 + 79aa994 commit ab713dd

File tree

4 files changed

+61
-2
lines changed

4 files changed

+61
-2
lines changed

src/spark_protocol.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,10 +445,22 @@ int SparkProtocol::variable_value(unsigned char *buf,
445445
return buflen;
446446
}
447447

448-
// Returns true on success, false on sending timeout failure
448+
// Returns true on success, false on sending timeout or rate-limiting failure
449449
bool SparkProtocol::send_event(const char *event_name, const char *data,
450450
int ttl, EventType::Enum event_type)
451451
{
452+
static system_tick_t recent_event_ticks[5] = { -1000, -1000, -1000, -1000, -1000 };
453+
static int evt_tick_idx = 0;
454+
455+
system_tick_t now = recent_event_ticks[evt_tick_idx] = callback_millis();
456+
evt_tick_idx++;
457+
evt_tick_idx %= 5;
458+
if (now - recent_event_ticks[evt_tick_idx] < 1000)
459+
{
460+
// exceeded allowable burst of 4 events per second
461+
return false;
462+
}
463+
452464
uint16_t msg_id = next_message_id();
453465
size_t msglen = event(queue + 2, msg_id, event_name, data, ttl, event_type);
454466

tests/ConstructorFixture.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,9 +295,11 @@ void ConstructorFixture::mock_signal(bool on)
295295
signal_called_with = on;
296296
}
297297

298+
system_tick_t ConstructorFixture::next_millis = 0;
299+
298300
system_tick_t ConstructorFixture::mock_millis(void)
299301
{
300-
return 0;
302+
return next_millis;
301303
}
302304

303305
bool ConstructorFixture::mock_ota_status_check(void)

tests/ConstructorFixture.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ struct ConstructorFixture
5353
static void mock_signal(bool on);
5454
static bool signal_called_with;
5555
static int variable_to_get;
56+
static system_tick_t next_millis;
5657
static system_tick_t mock_millis(void);
5758
static bool mock_ota_status_check(void);
5859
static SparkReturnType::Enum mock_variable_type(const char *variable_key);

tests/TestSparkProtocol.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,4 +317,48 @@ SUITE(SparkProtocolConstruction)
317317
spark_protocol.send_event("lake-depth/1", "28m", 21600, EventType::PRIVATE);
318318
CHECK_ARRAY_EQUAL(expected, sent_buf_0, 34);
319319
}
320+
321+
TEST_FIXTURE(ConstructorFixture, PublishingBurst4EventsSucceeds)
322+
{
323+
bool success[4];
324+
next_millis = 1000;
325+
success[0] = spark_protocol.send_event("a", NULL, 60, EventType::PUBLIC);
326+
success[1] = spark_protocol.send_event("b", NULL, 60, EventType::PUBLIC);
327+
success[2] = spark_protocol.send_event("c", NULL, 60, EventType::PUBLIC);
328+
success[3] = spark_protocol.send_event("d", NULL, 60, EventType::PUBLIC);
329+
CHECK(success[0] && success[1] && success[2] && success[3]);
330+
}
331+
332+
TEST_FIXTURE(ConstructorFixture, PublishingBurst5EventsFails)
333+
{
334+
bool success[5];
335+
next_millis = 2000;
336+
success[0] = spark_protocol.send_event("a", NULL, 60, EventType::PUBLIC);
337+
success[1] = spark_protocol.send_event("b", NULL, 60, EventType::PUBLIC);
338+
success[2] = spark_protocol.send_event("c", NULL, 60, EventType::PUBLIC);
339+
success[3] = spark_protocol.send_event("d", NULL, 60, EventType::PUBLIC);
340+
success[4] = spark_protocol.send_event("e", NULL, 60, EventType::PUBLIC);
341+
CHECK(success[0] && success[1] && success[2] && success[3] && !success[4]);
342+
}
343+
344+
TEST_FIXTURE(ConstructorFixture, PublishingBurst4Wait1SBurst4AgainSucceeds)
345+
{
346+
bool success[4];
347+
348+
next_millis = 3000;
349+
success[0] = spark_protocol.send_event("a", NULL, 60, EventType::PUBLIC);
350+
success[1] = spark_protocol.send_event("b", NULL, 60, EventType::PUBLIC);
351+
success[2] = spark_protocol.send_event("c", NULL, 60, EventType::PUBLIC);
352+
success[3] = spark_protocol.send_event("d", NULL, 60, EventType::PUBLIC);
353+
bool first_burst_success = success[0] && success[1] && success[2] && success[3];
354+
355+
next_millis = 4000;
356+
success[0] = spark_protocol.send_event("a", NULL, 60, EventType::PUBLIC);
357+
success[1] = spark_protocol.send_event("b", NULL, 60, EventType::PUBLIC);
358+
success[2] = spark_protocol.send_event("c", NULL, 60, EventType::PUBLIC);
359+
success[3] = spark_protocol.send_event("d", NULL, 60, EventType::PUBLIC);
360+
bool second_burst_success = success[0] && success[1] && success[2] && success[3];
361+
362+
CHECK(first_burst_success && second_burst_success);
363+
}
320364
}

0 commit comments

Comments
 (0)