hypothesis / lms

LTI app for integrating with learning management systems
BSD 2-Clause "Simplified" License
46 stars 14 forks source link

Race condition creating assignments in non-Canvas LMSes #5714

Open sentry-io[bot] opened 1 year ago

sentry-io[bot] commented 1 year ago

This exception might be reproducible in other ways but it's trivial to, in any non canvas LMS to:

Not sure what the right solution is:

This last option could be extended with a prompt to decide what to do, which might complicate things.


Sentry Issue: LMS-BACKEND-WX

UniqueViolation: duplicate key value violates unique constraint "uq__assignment__resource_link_id"
DETAIL:  Key (resource_link_id, tool_consumer_instance_guid)=(17688, moodle.uleth.ca) already exists.

  File "sqlalchemy/engine/base.py", line 1965, in _exec_single_context
    self.dialect.do_execute(
  File "sqlalchemy/engine/default.py", line 921, in do_execute
    cursor.execute(statement, parameters)
  File "newrelic/hooks/database_psycopg2.py", line 61, in execute
    return super(CursorWrapper, self).execute(sql, parameters, *args, **kwargs)
  File "newrelic/hooks/database_dbapi2.py", line 37, in execute
    return self.__wrapped__.execute(sql, parameters,

IntegrityError: (raised as a result of Query-invoked autoflush; consider using a session.no_autoflush block if this flush is occurring prematurely)
(psycopg2.errors.UniqueViolation) duplicate key value violates unique constraint "uq__assignment__resource_link_id"
DETAIL:  Key (resource_link_id, tool_consumer_instance_guid)=(17688, moodle.uleth.ca) already exists.

[SQL: INSERT INTO assignment (resource_link_id, tool_consumer_instance_guid, copied_from_id, document_url, extra, is_gradable, title, description) VALUES (%(resource_link_id)s, %(tool_consumer_instance_guid)s, %(copied_from_id)s, %(document_url)s, %(extra)s, %(is_gradable)s, %(title)s, %(description)s) RETURNING assignment.id, assignment.created, assignment.updated]
[parameters: {'resource_link_id': '17688', 'tool_consumer_instance_guid': 'moodle.uleth.ca', 'copied_from_id': None, 'document_url': 'https://drive.google.com/uc?id=1JQ1E3WnoAYKRYEBf38ftTc5ovnzYKTZy&export=download', 'extra': '{"group_set_id": ""}', 'is_gradable': False, 'title': 'Vinyeta annotation'...
(39 additional frame(s) were not displayed)
...
  File "lms/validation/__init__.py", line 92, in wrapper_view
    return view(context, request)
  File "lms/views/lti/basic_launch.py", line 117, in configure_assignment_callback
    return self._show_document(assignment)
  File "lms/views/lti/basic_launch.py", line 149, in _show_document
    self.request.find_service(name="lti_h").sync(
  File "lms/services/lti_h.py", line 48, in sync
    self._group_info_service.upsert_group_info(
  File "lms/services/group_info.py", line 30, in upsert_group_info
    self._db.query(GroupInfo)
seanh commented 1 year ago

Not sure what the right solution is:

  1. Ignore this. It doesn't happen that often.

  2. The second configuration overrides the first one. Could potentially be confusing

  3. The second configuration gets ignored. Also, could be confusing.

  4. We show an error, "Hey you already configured this"

I'd say either 2 or 4, not 3