Exemple #1
0
async def test_reclaim_lost_messages_one(redis_client: Redis, redis_pool):
    """Test that messages which another consumer has timed out on can be reclaimed"""

    # Add a message
    await redis_client.xadd(
        "my.dummy.my_event:stream",
        fields={
            b"api_name": b"my.dummy",
            b"event_name": b"my_event",
            b"id": b"123",
            b"version": b"1",
            b":field": b'"value"',
        },
    )
    # Create the consumer group
    await redis_client.xgroup_create(stream="my.dummy.my_event:stream",
                                     group_name="test_service",
                                     latest_id="0")

    # Claim it in the name of another consumer
    result = await redis_client.xread_group(
        group_name="test_service",
        consumer_name="bad_consumer",
        streams=["my.dummy.my_event:stream"],
        latest_ids=[">"],
    )
    assert result, "Didn't actually manage to claim any message"

    # Sleep a moment to fake a short timeout
    await asyncio.sleep(0.1)

    event_transport = RedisEventTransport(
        redis_pool=redis_pool,
        service_name="test_service",
        consumer_name="good_consumer",
        acknowledgement_timeout=0.01,  # in ms, short for the sake of testing
        stream_use=StreamUse.PER_EVENT,
    )
    reclaimer = event_transport._reclaim_lost_messages(
        stream_names=["my.dummy.my_event:stream"],
        consumer_group="test_service",
        expected_events={"my_event"},
    )

    reclaimed_messages = []
    async for m in reclaimer:
        reclaimed_messages.extend(m)
        for m in reclaimed_messages:
            await event_transport.acknowledge(m)

    assert len(reclaimed_messages) == 1
    assert reclaimed_messages[0].native_id
    assert type(reclaimed_messages[0].native_id) == str

    result = await redis_client.xinfo_consumers("my.dummy.my_event:stream",
                                                "test_service")
    consumer_info = {r[b"name"]: r for r in result}

    assert consumer_info[b"bad_consumer"][b"pending"] == 0
    assert consumer_info[b"good_consumer"][b"pending"] == 0
Exemple #2
0
async def test_reclaim_lost_messages_many(loop, redis_client, redis_pool,
                                          dummy_api):
    """Test that messages keep getting reclaimed until there are none left"""

    # Add 20 messages
    for x in range(0, 20):
        await redis_client.xadd(
            "my.dummy.my_event:stream",
            fields={
                b"api_name": b"my.dummy",
                b"event_name": b"my_event",
                b"id": b"123",
                b"version": b"1",
                b":field": b'"value"',
            },
        )

    # Create the consumer group
    await redis_client.xgroup_create(stream="my.dummy.my_event:stream",
                                     group_name="test_service",
                                     latest_id="0")

    # Claim them all in the name of another consumer
    result = await redis_client.xread_group(
        group_name="test_service",
        consumer_name="bad_consumer",
        streams=["my.dummy.my_event:stream"],
        latest_ids=[">"],
        count=20,
    )
    assert result, "Didn't actually manage to claim any message"

    # Sleep a moment to fake a short timeout
    await asyncio.sleep(0.1)

    event_transport = RedisEventTransport(
        redis_pool=redis_pool,
        service_name="test_service",
        consumer_name="good_consumer",
        acknowledgement_timeout=0.01,  # in ms, short for the sake of testing
        stream_use=StreamUse.PER_EVENT,
        reclaim_batch_size=
        5,  # Less than 20 (see message creation above), so multiple fetches required
    )

    reclaimer = event_transport._reclaim_lost_messages(
        stream_names=["my.dummy.my_event:stream"],
        consumer_group="test_service",
        expected_events={"my_event"},
    )

    # We should get 20 unique IDs back (i.e. no duplicates, nothing missed)
    messages = chain(*[m async for m in reclaimer])
    message_ids = {m.native_id for m in messages}
    assert len(message_ids) == 20
Exemple #3
0
async def test_reclaim_lost_messages_ignores_non_timed_out_messages(
        redis_client, redis_pool):
    """Ensure messages which have not timed out are not reclaimed"""

    # Add a message
    await redis_client.xadd(
        "my.dummy.my_event:stream",
        fields={
            b"api_name": b"my.dummy",
            b"event_name": b"my_event",
            b"id": b"123",
            b":field": b'"value"',
        },
    )
    # Create the consumer group
    await redis_client.xgroup_create(stream="my.dummy.my_event:stream",
                                     group_name="test_service",
                                     latest_id="0")

    # Claim it in the name of another consumer
    await redis_client.xread_group(
        group_name="test_service",
        consumer_name="bad_consumer",
        streams=["my.dummy.my_event:stream"],
        latest_ids=[">"],
    )
    # Sleep a moment to fake a short timeout
    await asyncio.sleep(0.1)

    event_transport = RedisEventTransport(
        redis_pool=redis_pool,
        service_name="test_service",
        consumer_name="good_consumer",
        # in ms, longer as we want to check that the messages is not reclaimed
        acknowledgement_timeout=0.9,
        stream_use=StreamUse.PER_EVENT,
    )
    reclaimer = event_transport._reclaim_lost_messages(
        stream_names=["my.dummy.my_event:stream"],
        consumer_group="test_service",
        expected_events={"my_event"},
    )
    reclaimed_messages = [m async for m in reclaimer]
    assert len(reclaimed_messages) == 0
Exemple #4
0
async def test_reclaim_lost_messages_different_event(redis_client: Redis,
                                                     redis_pool):
    """Test that messages which another consumer has timed out on can be reclaimed

    However, in this case we have a single stream for an entire API. The stream
    has a lost message for an event we are not listening for. In this case the
    event shouldn't be claimed
    """

    # Add a message
    await redis_client.xadd(
        "my.dummy.*:stream",
        fields={
            b"api_name": b"my.dummy",
            b"event_name": b"my_event",
            b"id": b"123",
            b"version": b"1",
            b":field": b'"value"',
        },
    )
    # Create the consumer group
    await redis_client.xgroup_create(stream="my.dummy.*:stream",
                                     group_name="test_service",
                                     latest_id="0")

    # Claim it in the name of another consumer
    result = await redis_client.xread_group(
        group_name="test_service",
        consumer_name="bad_consumer",
        streams=["my.dummy.*:stream"],
        latest_ids=[">"],
    )
    assert result, "Didn't actually manage to claim any message"

    # Sleep a moment to fake a short timeout
    await asyncio.sleep(0.1)

    event_transport = RedisEventTransport(
        redis_pool=redis_pool,
        service_name="test_service",
        consumer_name="good_consumer",
        acknowledgement_timeout=0.01,  # in ms, short for the sake of testing
        stream_use=StreamUse.PER_API,
    )
    reclaimer = event_transport._reclaim_lost_messages(
        stream_names=["my.dummy.*:stream"],
        consumer_group="test_service",
        expected_events={"another_event"
                         },  # NOTE: We this is NOT the event we created above
    )

    reclaimed_messages = []
    async for m in reclaimer:
        reclaimed_messages.extend(m)
        for m in reclaimed_messages:
            await event_transport.acknowledge(m)

    assert len(reclaimed_messages) == 0

    result = await redis_client.xinfo_consumers("my.dummy.*:stream",
                                                "test_service")
    consumer_info = {r[b"name"]: r for r in result}

    assert consumer_info[b"bad_consumer"][b"pending"] == 0
    assert consumer_info[b"good_consumer"][b"pending"] == 0