Repository: getsentry/sentry

Issue:
Event navigation busted if two events have same timestamp
If some of the events in a group have identical values for 'datetime' (down to the second), the "newer event"/"older event" buttons end up navigating in an endless loop for such events.

(version 6.2.3)

Here are some fix possibilities:
1. increase the granularity of the DB column to timestamp-plus-sub-second. But it looks like that's not possible in Django (https://code.djangoproject.com/ticket/19716)
2. use something like an IntegerField instead of a DateTimeField, representing milliseconds-since-1970 and piping this thru something like time.ctime()
3. if you can guarantee that  event.PK values are higher for later events, sort via "ORDER BY datetime, id" instead of just "ORDER BY datetime", e.g. in web.frontend.groups.render_with_group_context():

```
<<                next_event = base_qs.filter(datetime__gte=event.datetime).order_by('datetime')[0:1].get()
--------
>>                next_event = base_qs.filter(datetime__gte=event.datetime,id__gt=event.id).order_by('datetime')[0:1].get()
```



Discussion:
OK, I tried option (3) above and it doesn't work, but maybe something in that direction.

Or maybe there could be a list of links for _all_ events in the group so you can jump past the troublesome ones that just ping-pong back and forth to each other when you click on "newer"/"older".

we can do >= datetime, exclude self, order by datetime, id

I'm not sure if that'd help - if two events have the timestamp they'd just ping-pong back to each other in an endless loop:

```
id | datetime
1 | 2013-12-03 01:01:01
2 | 2013-12-03 01:01:01
```

If you're currently viewing event 1, the query for "later" would yield event 2.
Similarly, if you're viewing event 2, the query would yield event 1.

It'd only work if you could do >= id ... but that hinges on the note above in (3) ("event.PK values are higher for later events")

Couldn't the ordering simply be by `datetime` and then `pk`? There's no guarantee that the two events _actually_ occurred in that order, but there's no getting around that, and it's better to have at least some order defined.

I just tried that in our sentry instance, seems to work just fine. I'll submit a pull request.


Resolving patch:
diff --git a/src/sentry/web/frontend/groups.py b/src/sentry/web/frontend/groups.py
--- a/src/sentry/web/frontend/groups.py
+++ b/src/sentry/web/frontend/groups.py
@@ -141,12 +141,12 @@ def render_with_group_context(group, template, context, request=None,
         if event.id:
             base_qs = group.event_set.exclude(id=event.id)
             try:
-                next_event = base_qs.filter(datetime__gte=event.datetime).order_by('datetime')[0:1].get()
+                next_event = base_qs.filter(datetime__gte=event.datetime, pk__gte=event.pk).order_by('datetime', 'pk')[0:1].get()
             except Event.DoesNotExist:
                 next_event = None
 
             try:
-                prev_event = base_qs.filter(datetime__lte=event.datetime).order_by('-datetime')[0:1].get()
+                prev_event = base_qs.filter(datetime__lte=event.datetime, pk__lte=event.pk).order_by('-datetime', '-pk')[0:1].get()
             except Event.DoesNotExist:
                 prev_event = None
         else:


Test patch: