Django threadsafe get_or_create具有外部连接

时间:2014-01-30 20:02:40

标签: mysql django multithreading thread-safety greenlets

假设我有一个符合this answer的替换get_or_create方法,除了我需要将此数据库事务与外部API调用相结合(检查是否存在S3存储桶)。 假设数据库级别存在唯一约束(MySQL InnoDB)。我正在使用eventlet在多个Gunicorn工作进程中运行此代码。

@transaction.commit_on_success
def get_or_create_with_func(obj, func_to_call=None, **kwargs):
    try:
        result, created = obj.objects.create(**kwargs), True
    except IntegrityError:
        transaction.commit()
        result, created = obj.objects.get(**kwargs), False

    func_result = None
    if func_to_call is not None and created:
        func_result = func_to_call()

    return result, created, func_result

交易的成功取决于func_to_call成功返回(不会引发异常)。如果它引发异常,显然事务将回滚。

我不确定的是,如果2个线程同时使用此函数,create仍会保存数据库的条目(以便IntegrityError被引发,{{1}调用返回一个对象),还是必须“等待”直到get完成?

基本上我正在想象这个场景,上面的函数调用如下:

func_to_call
  1. 线程1和2几乎同时呼叫query_result, created, func_result = get_or_create_with_func(MyModel, external_api_func, model_column=some_value)
  2. 他们都尝试通过get_or_create_with_func
  3. 创建条目
  4. 假设线程1成功创建它。然后它退出try / except块,然后执行obj.objects.create
  5. 线程2也尝试创建对象。
  6. 理想情况下,主题2会遇到func_to_call
  7. 线程1完成调用IntegrityError,它不会引发异常。
  8. 线程2“提交”(并且线程1也已完成提交),因此它可以调用func_to_call,并按预期获取线程1写入的DB对象。
  9. OR

    1. 主题1调用get 并引发异常
    2. 线程1导致django回滚事务,因此DB条目不存在。
    3. 线程2应该仍然会遇到func_to_call,但现在调用IntegrityError将不会返回任何对象,因为线程1回滚了事务。
    4. 我的问题是,在第4步,由于表上的唯一约束,get会失败,或者它会经历,因为线程1还没有真正提交事务(让我们说{{1}很慢)?

0 个答案:

没有答案