1
\$\begingroup\$

I have a FastAPI app that uses Celery and depends on DB transactions. I'm a little confused as to where the DB transaction should occur--Whether it should be run inside the Celery task definition, or whether it should be run in the endpoint (route) definition. I expect this endpoint to be simultaneously, potentially, so I need the event to not delay significantly but rather be added to a queue, hence the celery.

Transacting in the route definition:

@router.get("/user-form/")
def user_signup(session: Session = Depends(get_db_session)):
    try:
        username = random_username()
        user = User(
            username=f'{username}',
            email=f'{username}@test.com',
        )
        session.add(user)
        session.commit()
    except Exception as e:
        session.rollback()
        raise

    return {"message": "done"}

Or run the DB transaction in a Celery task:

@router.get("/user-form/")
def user_signup(session: Session = Depends(get_db_session)):
    try:
        username = random_username()
        user = User(
            username=f'{username}',
            email=f'{username}@test.com',
        )
        insert_user.delay(user) #<--Enqueue to Celery here
    except Exception as e:
        session.rollback()
        raise

    return {"message": "done"}

# Celery
@shared_task()
def insert_user(user):
    from project.users.models import User

    with db_context() as session:
        try:
           session.add(user)
           session.commit()
        except Exception as e:
           session.rollback()
           raise

I'd like the DB transactions to be in a queue in case they pile up and I need to prevent app delays. Thank you for your suggestions.

\$\endgroup\$
3
  • \$\begingroup\$ Welcome to Code Review! Please edit your question so that the title describes the purpose of the code, rather than its mechanism. We really need to understand the motivational context to give good reviews. Thanks! \$\endgroup\$ Jan 14 at 13:41
  • \$\begingroup\$ Just throwing in my $0.02; decoupling the user insertion logic from the HTTP server logic will have great benefits (ignoring the context of Celery). Say you want to develop a CLI for your app in the future; now your user signup command can easily be implemented because the insertion logic is decoupled. Also, unit testing. \$\endgroup\$
    – Luke Carr
    Jan 14 at 14:23
  • \$\begingroup\$ @LukeCarr Interesting idea. So I could extract all the transactional logic into a separate transaction method, then the API could call to it through the Celery task. Thanks for the suggestion. \$\endgroup\$
    – RichardS
    Jan 14 at 16:20

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.