Repository: getsentry/sentry

Issue:
BufferError: Local: Queue full
I am receiving this error once every 2-4 days and I need to restart Sentry to fix it. This started after moving to the Docker version of Sentry.

I never noticed this being an issue on 9.1.2 also with Clickhouse and Snuba running, but without Kafka.

> https://observ.app/share/issue/4e4f208a500d48cc898770930706959a/

I am not sure where to look / poke / monitor to see this queue that is being spoken of and how I can flush it / enlarge it if needed.

`sentry queues list` showed all 0's so it's not looking like there is a massive backlog of events.

Any help is appreciated!


Discussion:
It seems like `.poll()` should be called somewhere to flush this queue according to this: https://github.com/confluentinc/confluent-kafka-dotnet/issues/703#issuecomment-574307498.

I'm sure this can be done in other parts of the code too so it might be happening, but currently I have to restart Sentry every X messages it seems like.
I am facing exactly same thing after 40 hours of uptime. Every event produces this error. All queues from `sentry queues list` are empty.

```
06:37:35 [ERROR] sentry: Local: Queue full
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/sentry/web/api.py", line 406, in dispatch
    request, helper, project_config, origin=origin, *args, **kwargs
  File "/usr/local/lib/python2.7/site-packages/sentry/web/api.py", line 492, in _dispatch
    **kwargs
  File "/usr/local/lib/python2.7/site-packages/django/views/generic/base.py", line 88, in dispatch
    return handler(request, *args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/sentry/web/api.py", line 559, in post
    event_id = self.process(request, data=data, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/sentry/web/api.py", line 638, in process
    event_manager, project, key, remote_addr, helper, attachments, project_config
  File "/usr/local/lib/python2.7/site-packages/sentry/web/api.py", line 245, in process_event
    category=data_category,
  File "/usr/local/lib/python2.7/site-packages/sentry/utils/outcomes.py", line 162, in track_outcome
    "quantity": quantity,
  File "/usr/local/lib/python2.7/site-packages/sentry/utils/pubsub.py", line 75, in publish
    self.producer.produce(topic=channel, value=value, key=key)
BufferError: Local: Queue full
```

So could anybody add `poll` here https://github.com/getsentry/sentry/blob/master/src/sentry/utils/pubsub.py#L75? 

Some more metadata from last line:
```
channel | 'outcomes'
key | None
self | <sentry.utils.pubsub.KafkaPublisher object at 0x7fb9e0ef4e90>
value | '{"category":0,"reason":"key_quota","outcome":2,"key_id":2,"event_id":"f394b43b73bf4e6994f4d34b18a60ecc","timestamp":"2020-04-08T06:01:25.732754Z","project_id":2,"org_id":1,"quantity":1}'
```




I’m not entirely sure why you’re getting it, but it’s being misdiagnosed. The local queue can’t flush because it’s unable to write to Kafka. Why it can’t write to Kafka, I don’t know. But that’s the issue. The only reason that queue will get full is if the broker is down or unable to accept data or something along those lines. So there’s nothing wrong here or anything wrong with what we’re doing. 
Also the “queue” in this case is referring to an in-memory queue being flushing/writing to Kafka since writes are async. Nothing will be yielded from `sentry queues list` since that’s explicitly for the celery queues. So rabbitmq or redis. 
> I’m not entirely sure why you’re getting it, but it’s being misdiagnosed. The local queue can’t flush because it’s unable to write to Kafka. Why it can’t write to Kafka, I don’t know. But that’s the issue. The only reason that queue will get full is if the broker is down or unable to accept data or something along those lines. So there’s nothing wrong here or anything wrong with what we’re doing.

I don't see any error logs in kafka container. And restarting only the `web` container is resolving this problem temporarily. So the problem must be in `web` container in kafka internal queue described here https://github.com/confluentinc/confluent-kafka-dotnet/issues/703#issuecomment-573777022
>  ...in python you need to do this (this is automatic in .net), otherwise the internal queue will fill up with delivery reports, and they'll never get removed.

Next thing I have noticed is that all events are processed by Sentry "just fine". So I can see them on Sentry Issue detail page. And in Sentry it looks like everything is working in spite of the _Queue full_ error is bombarding web container logs.
I have added `self.producer.poll(0)` above the `self.producer.produce(topic=channel, value=value, key=key)` line and problem seems to be resolved. No more buffer errors.

Btw. https://github.com/getsentry/sentry/blob/master/src/sentry/eventstream/kafka/backend.py#L52
@petrprikryl can you tell us if you see any outcomes data on your instance? You should see something under the path `/organizations/<org name>/stats/`. You may also click on the "Stats" link on the UI.
@BYK  it happened with us today,the errors came exclusively from a specific project, and it's the only one that uses filters for not accepting events, at the moment it happened there was 13,096‬ filtered events vs 12.862 queue full events. 

Note: We are using an Error Message inbound filtering for filtering the message
![image](https://user-images.githubusercontent.com/8229322/80711104-3674bf80-8ac6-11ea-9f4c-bcdaa735eb7e.png)
extra pic
@BYK  I validated it again (because it happened again) and removing the filters seems to have fixed it (at the cost of receiving spam) I feel like using the Discarded Feature will "fix" it but maybe it would be nice to see why such errors are happening if you get something around 3.5K filtered events in minutes
@ibm5155 it seems like this is indeed a missing `poll(0)` call as @petrprikryl suggested above. I'll verify and submit a patch.
Why don’t we have an issue with this ourselves in production? I’d be skeptical of slapping down a patch without understanding that. 

cc @getsentry/sns 
We do see this in Snuba from time to time, but only with a producer that follows a similar usage pattern as the one in Sentry. We haven't seen this in any producers that explicitly call `flush` (the main consumer calls flush immediately after producing batches of replacements, subscriptions continually calls poll in a separate thread.)
>Why don’t we have an issue with this ourselves in production?

We simply may have more resources at hand. Also, AFAIK relay would mitigate most of the issue for outcomes. /cc @jan-auer 

>I’d be skeptical of slapping down a patch without understanding that.

There are [multiple](https://github.com/confluentinc/confluent-kafka-python/issues/137#issuecomment-282427382) [issues](https://github.com/confluentinc/confluent-kafka-python/issues/16#issuecomment-231224794) on Kafka repo itself, strongly recommending the use of a `poll(0)` before or after a publish.

>We haven't seen this in any producers that explicitly call flush (the main consumer calls flush immediately after producing batches of replacements)

This is essentially making the call synchronous as `flush()` calls `poll()` until the pending queue is empty so that makes sense.

> subscriptions continually calls poll in a separate thread.)

This is also what Rust lib does from what I heard from @jan-auer which also supports adding the `poll(0)` call.

Resolving patch:
diff --git a/src/sentry/utils/pubsub.py b/src/sentry/utils/pubsub.py
--- a/src/sentry/utils/pubsub.py
+++ b/src/sentry/utils/pubsub.py
@@ -73,5 +73,7 @@ def __init__(self, connection, asynchronous=True):
 
     def publish(self, channel, value, key=None):
         self.producer.produce(topic=channel, value=value, key=key)
-        if not self.asynchronous:
+        if self.asynchronous:
+            self.producer.poll(0)
+        else:
             self.producer.flush()


Test patch: