2016-11-03 6 views
0

Ich benutze die ColdFusion-Gateways, um eine große Anzahl von Aktionen auszulösen und zu vergessen. Um dies zu tun, habe ich eine Schleife, die eine Abfrage mit einer SendGatewayMessage() am Ende durchläuft. Die Abfrage, die ich durchlaufen kann jedoch sehr groß werden. (100.000 Datensätze)Eine Warteschlange vor der Warteschlange

Um zu verhindern, dass Aktionen verloren gehen, habe ich die Größe der Warteschlange und die Anzahl der Threads erhöht.

Weil Aktionen immer noch verloren, ich vor den SendGatewayMessage() wie eine Schleife enthalten, so:

<cfloop condition="#gatewayService.getQueueSize()# GTE #gatewayService.getMaxQueueSize()#"> 
    <cfset guardianCount = guardianCount+1> 
</cfloop> 
<cflog file="gatewayGuardian" text="#i# waited for #guardianCount# iterations. Queuesize:#gatewayService.getQueueSize()#"> 
<cfset SendGatewayMessage("EventGateway",eventData)> 

(Mehr Infos auf der Gateway Klasse here)

Dies ist mehr oder weniger akzeptabel, da kann ich Englisch: www.mjfriendship.de/en/index.php?op...39&Itemid=32 Ich hoffe, dass der gesamte Prozess schneller und mit weniger Druck auf die Ressourcen des Servers laufen wird Server.

Irgendwelche Vorschläge? Irgendwelche Gedanken über die Konsequenzen einer weiteren Erhöhung der Warteschlangengröße?

+3

Ich würde nach Möglichkeiten suchen, um die Menge der Daten zu reduzieren, die Sie verarbeiten. –

+0

@DanBracuk Das wäre natürlich optimal. Aber die Menge der zu verarbeitenden Daten ist nicht wirklich verhandelbar ... Ich könnte versuchen, es zu zerschneiden, aber die Hauptsache, die ich versuche, ist die Verarbeitung so vieler Datensätze möglich mit einer Anfrage, die so kurz wie möglich ist .... – Sander

+0

Wenn Sie Gateway GatewayService wirklich nicht ändern können, gibt es wirklich nicht viel, was Sie hier tun können. Sie könnten die '' ändern, aber ich bezweifle, dass das einen großen Unterschied machen würde. –

Antwort

1

Momentan verwende ich Anwendungsvariablen, um die Datensätze im gesamten Job, die Anzahl der bereits verarbeiteten Stapel und die Anzahl der verarbeiteten Datensätze zu verfolgen. Zu Beginn der Arbeit, habe ich ein Stück Code, der wie so all diese Variablen initiiert:

<cfif not structKeyExists(application,"batchNumber") or application.batchNumber 
eq 0 or application.batchNumber eq ""> 
    <cfset application.batchNumber = 0> 
    <cfset application.recordsToDo = 0> 
    <cfset application.recordsDone = 0> 
    <cfset application.recordsDoneErrors = 0> 
</cfif> 

Danach, habe ich alle Datensätze in einer Abfrage und bestimmen, die wir in dieser Abfrage aufzeichnet müssen Prozess im aktuellen Batch. Die Anzahl der Datensätze im Stapel wird durch die Gesamtanzahl der Datensätze und die maximale Größe der Warteschlange bestimmt. Auf diese Weise belegt jeder Stapel nie mehr als etwa die Hälfte der Warteschlange. Dadurch wird sichergestellt, dass der Job niemals andere Vorgänge oder Jobs beeinträchtigt und dass die ursprüngliche Anforderung nicht überschritten wird.

Dann Schleife ich die Abfrage mit einer von/nach-Schleife, um die Gateway-Ereignisse auszulösen. Ich behielt den Wächter, damit es nie einen verlorenen Rekord geben wird, weil die Schlange voll ist.

Immer wenn ein Datensatz fertig ist, habe ich eine Funktion, die die Anzahl der Done gegen die Anzahl der Datensätze überprüft. Wenn sie gleich sind, bin ich fertig. Andernfalls müssen wir möglicherweise eine neue Charge starten. Beachten Sie, dass die Überprüfung, um zu sehen, ob wir fertig sind, in einem cflock ist, aber der eigentliche Ereignisbeitrag ist nicht. Dies liegt daran, dass Sie andernfalls einen Deadlock erhalten, wenn das von Ihnen gepostete Ereignis die Variablen, die Sie innerhalb der Sperre verwenden, nicht lesen kann.

Ich hoffe, dass dies von Nutzen ist, jemand oder jemand anderes hat eine bessere Idee noch.

<cflock timeout="30" name="jobResult"> 
    <cfset application.recordsDone++> 
    <cfif application.recordsDone eq application.recordsToDo> 
     <!--- We are done. Set all the application variables we used back to zero, so they do not get in the way when we start the job again ---> 
     <cfset application.batchNumber = 0> 
     <cfset application.recordsToDo = 0> 
     <cfset application.recordsDone = 0> 
     <cfset application.recordsPerBatch = 0> 
     <cfset application.recordsDoneErrors = 0> 
     <cfset application.JobStarted = 0> 
     <!--- If the number of records we have done is the same as the number of records in a batch times the current batchnumber plus one, we are done with the batch. ---> 
    <cfelseif application.recordsDone eq application.recordsPerBatch*(application.batchNumber+1) 
     and application.recordsDone neq application.recordsToDo> 
     <cfset application.batchNumber++> 
     <cfset doEventAnnounce = true> 
    </cfif> 
</cflock> 
<cfif doEventAnnounce> 
<!--- Fire off the event that starts the job. All the info it needs is in the applicationscope. ---> 
    <cfhttp url="#URURLHERE#/index.cfm" method="post"> 
     <cfhttpparam type="url" name="event" value="startBigJob"> 
    </cfhttp> 
</cfif> 
+0

IMO, diese Art von Batch-Prozess sollte db-gesteuert werden, so dass Sie nur die Daten für den aktuellen Batch, dh X Datensätze, ziehen, und der letzte bekannte Zustand bleibt bestehen, auch wenn die Anwendung neu gestartet wird. – Leigh