-
Notifications
You must be signed in to change notification settings - Fork 217
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
# Conflicts: # frontera/contrib/messagebus/kafkabus.py
- Loading branch information
1 parent
a26a0a9
commit 63e108d
Showing
4 changed files
with
128 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
from math import ceil | ||
|
||
import hashlib | ||
from cachetools import LRUCache | ||
from msgpack import Packer, unpackb | ||
from random import randint | ||
from six import MAXSIZE | ||
from struct import pack | ||
|
||
|
||
def random_bytes(): | ||
return pack("L", randint(0, MAXSIZE)) | ||
|
||
|
||
class FramedTransport(object): | ||
def __init__(self, max_message_size): | ||
self.max_message_size = max_message_size | ||
self.buffer = LRUCache(10) | ||
self.packer = Packer() | ||
|
||
def read(self, kafka_msg): | ||
frame = unpackb(kafka_msg.value) | ||
seg_id, seg_count, msg_key, msg = frame | ||
if seg_count == 1: | ||
return msg | ||
|
||
buffer = self.buffer.get(msg_key, dict()) | ||
if not buffer: | ||
self.buffer[msg_key] = buffer | ||
buffer[seg_id] = frame | ||
if len(buffer) == seg_count: | ||
msgs = [buffer[seg_id][3] for seg_id in sorted(buffer.keys())] | ||
final_msg = b''.join(msgs) | ||
del self.buffer[msg_key] | ||
return final_msg | ||
return None | ||
|
||
def write(self, key, msg): | ||
if len(msg) < self.max_message_size: | ||
yield self.packer.pack((0, 1, None, msg)) | ||
else: | ||
length = len(msg) | ||
seg_size = self.max_message_size | ||
seg_count = int(ceil(length / float(seg_size))) | ||
h = hashlib.sha1() | ||
h.update(msg) | ||
h.update(random_bytes()) | ||
msg_key = h.digest() | ||
for seg_id in range(seg_count): | ||
seg_msg = msg[seg_id * seg_size: (seg_id + 1) * seg_size] | ||
yield self.packer.pack((seg_id, seg_count, msg_key, seg_msg)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# -*- coding: utf-8 -*- | ||
from frontera.contrib.messagebus.kafka.transport import FramedTransport | ||
import random | ||
import string | ||
from collections import namedtuple | ||
import unittest | ||
|
||
KafkaMessage = namedtuple("KafkaMessage", ['key', 'value']) | ||
|
||
|
||
def get_blob(size): | ||
s = ''.join(random.choice(string.ascii_letters) for x in range(size)) | ||
return s.encode("latin1") | ||
|
||
|
||
class TestFramedTransport(unittest.TestCase): | ||
def setUp(self): | ||
self.transport = FramedTransport(32768) | ||
|
||
def test_big_message(self): | ||
test_msg = get_blob(1000000) | ||
assert len(test_msg) == 1000000 | ||
framed_msgs = [m for m in self.transport.write(b"key", test_msg)] | ||
assert len(framed_msgs) == 31 | ||
|
||
random.shuffle(framed_msgs) | ||
|
||
for i, msg in enumerate(framed_msgs): | ||
km = KafkaMessage(key=b"key", value=msg) | ||
result = self.transport.read(km) | ||
if i < len(framed_msgs) - 1: | ||
assert result is None | ||
assert result == test_msg # the last one is triggering msg assembling | ||
|
||
def test_common_message(self): | ||
test_msg = get_blob(4096) | ||
framed_msgs = [m for m in self.transport.write(b"key", test_msg)] | ||
assert len(framed_msgs) == 1 | ||
|
||
km = KafkaMessage(key=b"key", value=framed_msgs[0]) | ||
result = self.transport.read(km) | ||
assert result == test_msg |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters