diff --git a/calico/felix/actor.py b/calico/felix/actor.py index d035a87d880..85e0d1789bb 100644 --- a/calico/felix/actor.py +++ b/calico/felix/actor.py @@ -103,6 +103,7 @@ import gevent.local import logging import os +import random import sys import traceback import weakref @@ -395,7 +396,8 @@ def wait_and_check(async_results): r.get() -next_message_id = 0 +# Start with a random offset to make the log easier to grep. +next_message_id = random.randint(0, sys.maxint) class Message(object): @@ -494,8 +496,11 @@ def queue_fn(self, *args, **kwargs): # Allocate a message ID. We rely on there being no yield point # here for thread safety. global next_message_id - msg_id = next_message_id - next_message_id += 1 + msg_id = "M%016x" % next_message_id + if next_message_id == sys.maxint: + next_message_id = 0 + else: + next_message_id += 1 if not on_same_greenlet and not async: _stats.increment("Blocking calls started") diff --git a/calico/felix/test/test_actor.py b/calico/felix/test/test_actor.py index e07d77b4ba1..59fb3dbbe1b 100644 --- a/calico/felix/test/test_actor.py +++ b/calico/felix/test/test_actor.py @@ -22,7 +22,7 @@ import logging import itertools import gc -from contextlib import nested +import sys from gevent.event import AsyncResult import mock @@ -211,6 +211,23 @@ def test_yield(self, m_sleep): def test_wait_and_check_no_input(self): actor.wait_and_check([]) + def test_wrap_msg_id(self): + with mock.patch("calico.felix.actor.next_message_id"): + with mock.patch("calico.felix.actor.Message", autospec=True) as m_msg: + actor.next_message_id = sys.maxint + self._actor.do_a(async=True) + self._actor.do_a(async=True) + + self.assertEqual( + [c for c in m_msg.mock_calls if c[0] == ""], + [ + mock.call("M" + hex(sys.maxint)[2:], mock.ANY, mock.ANY, + mock.ANY, mock.ANY, needs_own_batch=mock.ANY), + mock.call("M0000000000000000", mock.ANY, mock.ANY, + mock.ANY, mock.ANY, needs_own_batch=mock.ANY), + ] + ) + class TestExceptionTracking(BaseTestCase):