2016-05-30 13 views
3

Ich habe eine Django-App, die Instagram imitiert, in dem Benutzer Fotos oder Meme hochladen, und dann ihre Fans von dem besagten Foto benachrichtigt werden.Der richtige Weg, um eine Aufgabe asynchron in Django durchzuführen, über Sellerie

Derzeit, um Benachrichtigungen zu senden, wenn ein Benutzer ein Foto hochlädt, ich Iterate durch jeden Fan der Uploader hat, hängen Sie die Benachrichtigungen an eine Liste, und dann bulk_create die Objekte. Wie in:

fans = UserFan.objects.filter(star=user).values_list('fan',flat=True) 
    fan_list = [] 
    for fan in fans: 
     fan_list.append(PhotoObjectSubscription(viewer_id=fan, which_photo=photo, updated_at=time, seen=False, type_of_object='1')) 
    PhotoObjectSubscription.objects.bulk_create(fan_list) 

Einfache Sachen. Beachten Sie, dass ich auch supervisord auf der VM meiner App installiert habe, wo ich einige rudimentäre Aufgaben über celery (mit redis als Nachrichtenbroker) ausführen kann.

Jetzt möchte ich die bulk_create Aufgabe oben als celery task ausführen; asynchron. Mein bulk_create Code befindet sich in der gleichen Ansicht, die auch für das Hochladen von Fotos verwendet wird. Ich rechne also damit, dass dies asynchron für den Benutzer beschleunigt wird.

Ich bin neu in celery Aufgaben, so kann über ein anschauliches Beispiel jemand darauf hinweisen, wie ich die oben genannte bulk_create Aufgabe in eine celery Aufgabe machen kann? Ich habe recherchiert, und hier ist das, was ich denke, ich tun muss:

1) In delay() am Ende der bulk_create Aussage:

PhotoObjectSubscription.objects.bulk_create(fan_list).delay() 

2) In tasks.py, fügen Sie eine neue Aufgabe zu verarbeiten die oben:

@task 
def bulk_create_notifications(): 
    PhotoObjectSubscription.objects.bulk_create(fan_list) 

3) keine Notwendigkeit, etwas zu CELERYBEAT_SCHEDULE in settings.py, hinzuzufügen, da die Aufgabe nicht eine periodische Aufgabe.

Ich bin wahrscheinlich nicht ganz richtig, also bitte helfen.

Antwort

3

Sie müssen fans passieren (man könnte es zu list werfen, wenn es tatsächlich ein ValuesListQuerySet ist) und alle anderen Dinge, die die Aufgabe Bedürfnisse (zB photo.id) als Argument für die Aufgabe:

@task 
def bulk_create_notifications(fans, photo_id): 
    fan_list = [] 
    for fan in fans: 
     fan_list.append(PhotoObjectSubscription(viewer_id=fan, which_photo_id=photo_id, updated_at=time, seen=False, type_of_object='1')) 
    PhotoObjectSubscription.objects.bulk_create(fan_list) 

dann können Sie asynchron die Aufgabe starten über:

# call delay on the task and pass it the same params you would pass to the fnc itself 
bulk_create_notifications.delay(fans) 

Da die Argumente gespeichert werden müssen und durch Ihre Aufgabenwarteschlange kommuniziert (redis) können Sie nur Argumente übergeben, die von der Serializer serializable sind Sie habe in deinen Einstellungen festgelegt (wahrscheinlich JSON). Das heißt, Sie sollten sich an einfache Typen halten. Zeichenfolgen, Ganzzahlen und Sie können keine Modellinstanzen oder Listen davon als Parameter übergeben.

Sie könnten natürlich noch höher starten und einfach user.id übergeben und alle db arbeiten in der Aufgabe.

+0

Nein. Das war ich falsch gelesen Ihren Code. Ich habe es bereits in der Antwort geändert. Sie können keine Modellinstanzen übergeben! Es könnte in Ihrem dev env funktionieren, wenn CELLERY_ALWAYS_EAGER auf "True" gesetzt ist, aber nicht, wenn die Parameter tatsächlich durch die Warteschlange geleitet werden. – schwobaseggl

+0

@HassanBaig Eigentlich ist 'fans' in Ihrem Code ein' ValuesListQuerySet', das Sie in 'list' umwandeln sollten, bevor Sie es an die Aufgabe übergeben. – schwobaseggl

+0

Bekam es. Ich werde es versuchen und ein wenig zurückkommen! –