Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to get retry working with unique constraint failure. #313

Closed
neonquill opened this Issue Nov 22, 2017 · 2 comments

Comments

Projects
None yet
2 participants
@neonquill
Copy link

neonquill commented Nov 22, 2017

I haven't been able to figure out how to get the retry parameter to work correctly with database errors. I can reproduce the test code with ZeroDivisionError exceptions, but not with database errors (such as a unique constraint violation).

Test code:

#!/usr/bin/env python3

from pony import orm

db = orm.Database()

class Foo(db.Entity):
    unique = orm.Required(int, unique=True)

@orm.db_session(retry=3)
def retry_unique():
    print("RETRY_UNIQUE")
    Foo(unique=1)

@orm.db_session(retry=3, retry_exceptions=[ZeroDivisionError])
def retry_zero_div():
    print("RETRY_ZERO_DIV")
    1/0

def main():
    db.bind(provider='postgres', user='postgres', password='password',
            host='127.0.0.1', database='test_retry')
    db.generate_mapping(create_tables=True)

    try:
        # This will run 4 times.
        retry_zero_div()
    except:
        pass

    try:
        # This will succeed (if db is empty).
        retry_unique()
        # This will only run once.  <- Bug?
        retry_unique()
    except:
        pass

if __name__ == '__main__':
    main()

Running this code on a clean database produces the following output:

RETRY_ZERO_DIV
RETRY_ZERO_DIV
RETRY_ZERO_DIV
RETRY_ZERO_DIV
RETRY_UNIQUE
RETRY_UNIQUE

I (correctly) see retry_zero_div() run 4 times (the first try plus the indicated 3 retries). For retry_unique() the first run succeeds (because there is no uniqueness violation) and then the second run throws an exception but is not re-tried (this seems wrong to me).

When I trace retry_zero_div() the retry gets caught in pony/pony/orm/core.py:462. However, when I run retry_unique() the code never hits that line. This makes me think that it's not an issue of having the wrong exceptions in retry_exceptions.

At this point, I'm not entirely sure if I'm doing something wrong or there is really a bug. Any advice would be appreciated.

@kozlovsky kozlovsky closed this in de6201c Nov 26, 2017

@kozlovsky kozlovsky added the bug label Nov 26, 2017

@kozlovsky kozlovsky self-assigned this Nov 26, 2017

@kozlovsky kozlovsky added this to the 0.7.4 milestone Nov 26, 2017

@kozlovsky

This comment has been minimized.

Copy link
Member

kozlovsky commented Nov 26, 2017

Thanks for reporting! It was a bug.

Previous code for retry handling assumed that exception is raised inside a function. In your example, the exception was raised outside of the function, when db_session tried to save changes to the database. Now such exceptions are processed correctly too.

@neonquill

This comment has been minimized.

Copy link
Author

neonquill commented Nov 27, 2017

Thanks for the fix and the explanation!

kozlovsky added a commit that referenced this issue Jul 23, 2018

Pony ORM Release 0.7.4 (2018-07-23)
# Major features

* Hybrid methods and properties added: https://docs.ponyorm.com/entities.html#hybrid-methods-and-properties
* Allow to base queries on another queries: `select(x.a for x in prev_query if x.b)`
* Added support of Python 3.7
* Added support of PyPy
* `group_concat()` aggregate function added
* pony.flask subpackage added for integration with Flask

# Other features

* `distinct` option added to aggregate functions
* Support of explicit casting to `float` and `bool` in queries

# Improvements

* Apply @cut_traceback decorator only when pony.MODE is 'INTERACTIVE'

# Bugfixes

* In SQLite3 `LIKE` is case sensitive now
* #249: Fix incorrect mixin used for Timedelta
* #251: correct dealing with qualified table names
* #301: Fix aggregation over JSON Column
* #306: Support of frozenset constants added
* #308: Fixed an error when assigning JSON attribute value to the same attribute: obj.json_attr = obj.json_attr
* #313: Fix missed retry on exception raised during db_session.__exit__
* #314: Fix AttributeError: 'NoneType' object has no attribute 'seeds'
* #315: Fix attribute lifting for JSON attributes
* #321: Fix KeyError on obj.delete()
* #325: duplicating percentage sign in raw SQL queries without parameters
* #331: Overriding __len__ in entity fails
* #336: entity declaration serialization
* #357: reconnect after PostgreSQL server closed the connection unexpectedly
* Fix Python implementation of between() function and rename arguments: between(a, x, y) -> between(x, a, b)
* Fix retry handling: in PostgreSQL and Oracle an error can be raised during commit
* Fix optimistic update checks for composite foreign keys
* Don't raise OptimisticCheckError if db_session is not optimistic
* Handling incorrect datetime values in MySQL
* Improved ImportError exception messages when MySQLdb, pymysql, psycopg2 or psycopg2cffi driver was not found
* desc() function fixed to allow reverse its effect by calling desc(desc(x))
* __contains__ method should check if objects belong to the same db_session
* Fix pony.MODE detection; mod_wsgi detection according to official doc
* A lot of inner fixes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.