Overview of the Issue
A webhook POST request was sent from the DRF server to the Django app server,
and during the process of creating a Post model instance in Django, the following issues arose.
- Webhook Response Timeout
- After the creation of the Post object, time was consumed for processing the
ManyToMany
fieldscategories
,tags
-
This caused a delay in the webhook response, and DRF recognized it as a failure
-
Data Integrity Not Secured
- When the Celery task was called immediately for subsequent processing, it was invoked at a point where
tags.add(...)
,categories.add(...)
operations were not yet completed -
This resulted in Celery processing incomplete data
-
Receiving empty data in Celery even after on_commit()
- After ensuring data integrity with
on_commit()
and scheduling the Celery task, the result of queries liketags.all()
still appeared as an empty list - This was due to Celery sending read operations to the replica DB, while there was a delay in synchronization from master to replica
Resolution Strategy
- Return Response Immediately After Post Creation
-
Create the Post instance and immediately return a
202 Accepted
response to DRF, avoiding the timeout issue -
Handle Subsequent Tasks in a Separate Thread
- Utilize
threading.Thread()
to separate relationship handling and Celery calling from the main flow -
Designed to prevent delays in the webhook response
-
Ensure Transaction Guarantee within post_process
- Wrap the entire
ManyToMany
field processing withintransaction.atomic()
- Schedule Celery tasks with
transaction.on_commit()
after task completion -
This ensures that Celery executes after the relationship processing is complete
-
Directly Specify the Master DB for Queries in Celery
- To prevent consistency issues caused by delays in the replica, explicitly use
using('default')
within the Celery task
post = Post.objects.using('default').get(id=post_id)
tags = post.tags.using('default').all()
categories = post.categories.using('default').all()
Alternatively, it is possible to route Celery requests to always query the master DB using a DB Router
Final Structure Summary
- DRF server → Django webhook request
- Django:
- Return response immediately after creating Post object
- Execute subsequent tasks in a separate thread
- Within the thread:
- Organize relationships with
atomic()
- Schedule Celery task with
on_commit()
- Organize relationships with
- Celery:
- Query data from the master DB (
default
)
- Query data from the master DB (
Conclusion
While all components function properly individually,
to resolve latency and data integrity issues arising in a distributed architecture environment,
a system design considering not just code structure but also data flow and timing, as well as delays in DB replicas was necessary.
Add a New Comment