cytoscape / appstore

Cytoscape App Store web application code
16 stars 20 forks source link

MultipleObjectsReturned #82

Open AlexanderPico opened 5 years ago

AlexanderPico commented 5 years ago

This error is back! The "fix" for the old site was to have a script run every hour to clear duplicates from mysql. Not an ideal solution. We should figure out when/how these duplicates are being created in the first place and fix it there.

If helpful, this particular instance started at around 1:00am PT on 28 Sept 2019 at which point the query for ReleaseDownloadsByDate for the MCODE app returned more than one object and throw the first error. Every attempt to download the app causes this error to repeat.

I suspect django is attempting to increment the download counter for the app and in retrieving the current value for the app for that particular day, it is getting TWO values instead of the expected one value.

Internal Server Error: /download/mcode/1.5.1
Traceback (most recent call last):
 File "/usr/local/lib/python3.6/dist-packages/django/core/handlers/base.py", line 132, in get_response
   response = wrapped_callback(request, *callback_args, **callback_kwargs)
 File "/var/www/CyAppStore/download/views.py", line 43, in release_download
   _increment_count(ReleaseDownloadsByDate, release = release, when = when)
 File "/var/www/CyAppStore/download/views.py", line 26, in _increment_count
   obj, created = klass.objects.get_or_create(**args)
 File "/usr/local/lib/python3.6/dist-packages/django/db/models/manager.py", line 127, in manager_method
   return getattr(self.get_queryset(), name)(*args, **kwargs)
 File "/usr/local/lib/python3.6/dist-packages/django/db/models/query.py", line 405, in get_or_create
   return self.get(**lookup), False
 File "/usr/local/lib/python3.6/dist-packages/django/db/models/query.py", line 338, in get
   (self.model._meta.object_name, num)
download.models.MultipleObjectsReturned: get() returned more than one ReleaseDownloadsByDate -- it returned 2!
AlexanderPico commented 5 years ago

This query will reveal the problematic records, e.g.:

mysql> select release_id, download_releasedownloadsbydate.when, count(*) as c 
    ->    from download_releasedownloadsbydate 
    ->    where release_id is not null 
    ->    group by release_id,download_releasedownloadsbydate.when having c > 1;
+------------+------------+---+
| release_id | when       | c |
+------------+------------+---+
|        869 | 2019-09-28 | 2 |
+------------+------------+---+

And this query will remove duplicates and resolve this error:

delete from download_releasedownloadsbydate where id in 
   (select max from (select MAX(id) as max, release_id, download_releasedownloadsbydate.when, count(*) as c 
   from download_releasedownloadsbydate 
   where release_id is not null 
   group by release_id,download_releasedownloadsbydate.when having c > 1) 
   as T);

As documented here: https://github.com/cytoscape/cytoscape/wiki/Cytoscape-App-Store#known-error-notifications

AlexanderPico commented 5 years ago

This blog post describes the potential problem with get_or_create, which is precisely where our error is occuring, see File "/var/www/CyAppStore/download/views.py", line 26, in _increment_count or also https://github.com/cytoscape/appstore/blob/master/download/views.py#L26.

The suggested fix is to enforce uniqueness, e.g., in our case, perhaps something like this...

unique_together = ("release", "when")

See https://docs.djangoproject.com/en/1.8/ref/models/options/#django.db.models.Options.unique_together

But I'm now confident where/how to implement/test this suggested fix... Any volunteers?

coleslaw481 commented 3 years ago

So this can also happen when release_id is NULL causing the same error. To catch this one must omit the release_id is not null from the query like so:

select release_id, download_releasedownloadsbydate.when, count(*) as c from download_releasedownloadsbydate group by release_id, download_releasedownloadsbydate.when having c>1;
+------------+------------+---+
| release_id | when       | c |
+------------+------------+---+
|       NULL | 2014-08-16 | 2 |
|       NULL | 2021-08-02 | 2 |
+------------+------------+---+
2 rows in set (4.11 sec)

I fixed this by removing one of the two entries above.