Hallo zusammen,
ich programmiere mit Django eine relativ große Webapplikation und es klappt alles soweit wunderbar. Ich bin aber auf ein kleines "Schönheitsproblem" gestoßen.
Ich versende über "EmailMultiAlternatives" (django.core.mail) html- bzw. text-eMails, das funktioniert auch wunderbar.
Das Problem ist jedoch, dass der eMail-Server nicht lokal läuft und so erst eine Verbindung zum Mailserver aufgebaut werden muss und das dauert immer etwas. Für den User hat das den Anschein, als ob der Befehl die eMail zu senden nicht angekommen ist, da die Programm-Abarbeitung hier "steht", bis die email korrekt versendet wurde. So kommt der Benutzer vielleicht auf die Idee nochmal zu klicken. Bei "EmailMultiAlternatives" kann jedoch ein Connection-Objekt angegeben werden. Sprich eine bestehende SMTP-Verbindung.
Wo bzw. wie kann eine solche SMTP-Verbindung schon vor dem versenden öffnen (z.B. beim Aufruf des Django-apps), dass das Versenden der Mail schneller von statten geht?
Kann ich das in sowas wie einem Konstruktor des jeweiligen App's angeben?
Vielen Dank.
(Django) SMTP-Verbindung offen halten?
Da für jeden Request ja Django ja quasi neu gestartet wird, funktioniert es prinzipiell nicht, dass etwas permanent läuft oder verbunden bleibt.
Dein Problem lässt sich tpyischerweise durch einen Queue-Service lösen, in den der Auftrag eine Mail zu verschicken eingestellt wird (was in der Regel sehr schnell geht) und dann später abgearbeitet wird, wenn Django schon wieder schläft und auf den nächsten Request wartet.
Im Prinzip kann man sich so was auch selbst bauen, in dem du in einem Tabelle einen passenden Eintrag schreibst und dann in einem zweiten Prozess (oder mehreren) regelmäßig in der Datenbank nachschaust, ob etwas zu tun ist und das dann tust.
Da dieser zweite Prozess vielleicht auch den ORM von Django benutzen will, ist es am einfachsten, ihn als custom commands zu implementieren, da diese aus der richtigen Umgebung direkt auf die Modelle zugreifen dürfen.
Statt einer Datenbank bietet sich auch häufig ein gemeinsamer Cache (z.B. memcached) an, da dies wesentlich effizienter ist. Und nicht jeder braucht ACID auf Queues, wie es z.B. JMS im Java-Umfeld bieten würde.
Schau dir mal http://code.google.com/p/django-queue-service/ an. Andere Stichworte sind Starling oder ActiveMQ, die haben aber nichts direkt mit Django zu tun. Vielleicht taugt http://code.google.com/p/peafowl/ etwas..?
Stefan
Dein Problem lässt sich tpyischerweise durch einen Queue-Service lösen, in den der Auftrag eine Mail zu verschicken eingestellt wird (was in der Regel sehr schnell geht) und dann später abgearbeitet wird, wenn Django schon wieder schläft und auf den nächsten Request wartet.
Im Prinzip kann man sich so was auch selbst bauen, in dem du in einem Tabelle einen passenden Eintrag schreibst und dann in einem zweiten Prozess (oder mehreren) regelmäßig in der Datenbank nachschaust, ob etwas zu tun ist und das dann tust.
Da dieser zweite Prozess vielleicht auch den ORM von Django benutzen will, ist es am einfachsten, ihn als custom commands zu implementieren, da diese aus der richtigen Umgebung direkt auf die Modelle zugreifen dürfen.
Statt einer Datenbank bietet sich auch häufig ein gemeinsamer Cache (z.B. memcached) an, da dies wesentlich effizienter ist. Und nicht jeder braucht ACID auf Queues, wie es z.B. JMS im Java-Umfeld bieten würde.
Schau dir mal http://code.google.com/p/django-queue-service/ an. Andere Stichworte sind Starling oder ActiveMQ, die haben aber nichts direkt mit Django zu tun. Vielleicht taugt http://code.google.com/p/peafowl/ etwas..?
Stefan
Die Idee mit dem Datenbankeintrag hatte ich auch schon, habe sie aber wieder verworfen, da ich sie nicht wirklich effizient gefunden habe. Aber ich gucke mir mal deine anderen Vorschläge an.sma hat geschrieben:Da für jeden Request ja Django ja quasi neu gestartet wird, funktioniert es prinzipiell nicht, dass etwas permanent läuft oder verbunden bleibt.
Dein Problem lässt sich tpyischerweise durch einen Queue-Service lösen, in den der Auftrag eine Mail zu verschicken eingestellt wird (was in der Regel sehr schnell geht) und dann später abgearbeitet wird, wenn Django schon wieder schläft und auf den nächsten Request wartet.
Im Prinzip kann man sich so was auch selbst bauen, in dem du in einem Tabelle einen passenden Eintrag schreibst und dann in einem zweiten Prozess (oder mehreren) regelmäßig in der Datenbank nachschaust, ob etwas zu tun ist und das dann tust.
Da dieser zweite Prozess vielleicht auch den ORM von Django benutzen will, ist es am einfachsten, ihn als custom commands zu implementieren, da diese aus der richtigen Umgebung direkt auf die Modelle zugreifen dürfen.
Statt einer Datenbank bietet sich auch häufig ein gemeinsamer Cache (z.B. memcached) an, da dies wesentlich effizienter ist. Und nicht jeder braucht ACID auf Queues, wie es z.B. JMS im Java-Umfeld bieten würde.
Schau dir mal http://code.google.com/p/django-queue-service/ an. Andere Stichworte sind Starling oder ActiveMQ, die haben aber nichts direkt mit Django zu tun. Vielleicht taugt http://code.google.com/p/peafowl/ etwas..?
Stefan
Eine andere Alternative wäre ein lokaler SMTP-(Queue)-Server, der nur von localhost Mails entgegennimmt in eine Warteschlange stellt und nacheinander an einen Smarthost verschickt. Das kann/macht eigentlich jeder Mailserver...
Werde vermtl. nicht um einen solchen, lokalen "Mini-Mailserver" herumkommen.
Vielen Dank dafür.
Hu, wie meinst du das? Es sollte ohne Probleme möglich sein eine Connection offen zu halten, kann mich nicht erinnern, dass da irgendwas neu gestartet wird...sma hat geschrieben:Da für jeden Request ja Django ja quasi neu gestartet wird, funktioniert es prinzipiell nicht, dass etwas permanent läuft oder verbunden bleibt.
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Ich finde auch dass ein Relay-Only SMTP-Server wie ESMTP oder MSMTP die für ihren Aufwand beste und simpelste Lösung ist.metty hat geschrieben:Eine andere Alternative wäre ein lokaler SMTP-(Queue)-Server, der nur von localhost Mails entgegennimmt in eine Warteschlange stellt und nacheinander an einen Smarthost verschickt. Das kann/macht eigentlich jeder Mailserver...
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
So kleine SMTP-Server sind genau das richtige für mich, denn ich wollte die Installation so schlank (und sicher) halten wie möglich...Leonidas hat geschrieben:Ich finde auch dass ein Relay-Only SMTP-Server wie ESMTP oder MSMTP die für ihren Aufwand beste und simpelste Lösung ist.metty hat geschrieben:Eine andere Alternative wäre ein lokaler SMTP-(Queue)-Server, der nur von localhost Mails entgegennimmt in eine Warteschlange stellt und nacheinander an einen Smarthost verschickt. Das kann/macht eigentlich jeder Mailserver...
ESMTP scheint hier genau das zu sein, was ich will
Ansonsten werde ich mal freshmeat.net konsultieren
apollo13 hat geschrieben:Hu, wie meinst du das? Es sollte ohne Probleme möglich sein eine Connection offen zu halten, kann mich nicht erinnern, dass da irgendwas neu gestartet wird...sma hat geschrieben:Da für jeden Request ja Django ja quasi neu gestartet wird, funktioniert es prinzipiell nicht, dass etwas permanent läuft oder verbunden bleibt.
Naja, django ist kein Server-Dienst. Ruft man z.B. .../meineseite/ auf, wird die jeweils zugeordnete Funktion "abgearbeitet", an deren Ende kann z.B. ein Template mit Daten versorgt werden, dann jedoch ist die Ausführung zu Ende.
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Jein. Es ist nicht definiert was passiert. Bei CGI-Applikationen ist die Ausführung an dieser Stelle zuende, aber bei FastCGI oder mod_wsgi läuft die Applikation auch nach dem Request noch weiter und kann in dieser Zeit was auch immer machen.metty hat geschrieben:Naja, django ist kein Server-Dienst. Ruft man z.B. .../meineseite/ auf, wird die jeweils zugeordnete Funktion "abgearbeitet", an deren Ende kann z.B. ein Template mit Daten versorgt werden, dann jedoch ist die Ausführung zu Ende.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Stimmt, das hatte ich vergessen...Leonidas hat geschrieben:Jein. Es ist nicht definiert was passiert. Bei CGI-Applikationen ist die Ausführung an dieser Stelle zuende, aber bei FastCGI oder mod_wsgi läuft die Applikation auch nach dem Request noch weiter und kann in dieser Zeit was auch immer machen.metty hat geschrieben:Naja, django ist kein Server-Dienst. Ruft man z.B. .../meineseite/ auf, wird die jeweils zugeordnete Funktion "abgearbeitet", an deren Ende kann z.B. ein Template mit Daten versorgt werden, dann jedoch ist die Ausführung zu Ende.
Jedoch habe ich bis jetzt von keiner Möglichkeit gehört eine Art "Dienst", wie eben eine SMTP-Verbindung offen zu halten, laufen zu lassen.
Aber wie gesagt, es gibt ein paar Relay-only SMTP Server bzw. sog. store and forward SMTP Server, die sollten hier genau das richtige sein.
http://emailrelay.sourceforge.net/ ist hier besonders einfach zu konfigurieren.
Einfach "emailrelay --as-server --poll 3600 --forward-to smarthost:smtp" und schon werden gespoolte Mails jede Stunde an einen Smarthost ausgeliefert.
Das ist aber ein Implementierungsdetail und das Konzept ist und bleibt, dass die Anwendung für einen Aufruf lebt und keinen Zustand bis zum nächsten Aufruf überlebt.Leonidas hat geschrieben:Jein. Es ist nicht definiert was passiert. Bei CGI-Applikationen ist die Ausführung an dieser Stelle zuende, aber bei FastCGI oder mod_wsgi läuft die Applikation auch nach dem Request noch weiter und kann in dieser Zeit was auch immer machen.metty hat geschrieben:Naja, django ist kein Server-Dienst. Ruft man z.B. .../meineseite/ auf, wird die jeweils zugeordnete Funktion "abgearbeitet", an deren Ende kann z.B. ein Template mit Daten versorgt werden, dann jedoch ist die Ausführung zu Ende.
Stefan
IMHO nicht, aber so kommen wir nicht weiter ;) Ich kann keinen Zustand in den nächsten Request rüberretten, denn möglicherweise haben ich 10 voneinander komplett unabhängige Betriebssystem-Prozesse, die beliebig sterben und neu geboren werden und wo auch nicht klar ist, welches Prozess als nächstes dran kommt. Ein geteilter globaler Zustand existiert einfach nicht. Die Anfrage ist unwiderruflich beendet, da ich sie nicht mehr von irgendwo referenzieren kann. Die Nicht-Erreichbarkeit von einem globalen Zustand aus ist aber gerade als tot definiert. Damit stirbt jeder Anfrage nach Erfüllung ihrer Lebensaufgabe, eine HTTP-Response zu generieren.
Die üblichen Rahmenwerke für Python oder Ruby funktionieren alle genau wie PHP nach dem "share nothing"-Prinzip. Wer's anders haben will, braucht einen dedizierten Anwendungsserver a la Zope oder JavaEE.
Stefan
Die üblichen Rahmenwerke für Python oder Ruby funktionieren alle genau wie PHP nach dem "share nothing"-Prinzip. Wer's anders haben will, braucht einen dedizierten Anwendungsserver a la Zope oder JavaEE.
Stefan