2016-11-03 19 views
0

ColdFusionゲートウェイを使用して多数のアクションを実行し、忘れてしまいます。これを行うには、最後にSendGatewayMessage()というクエリを実行するループがあります。ただし、ループするクエリは非常に大きくなる可能性があります。 (100.000+レコード)キューより先のキュー

アクションが失われないように、キューサイズとスレッド数を増やしました。

アクションはまだ失われてしまったので、私はそうのようなSendGatewayMessage()前にループが含まれていました。

<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)> 

(GatewayServiceのクラスhereの詳細情報)

を私ができるので、これは、多かれ少なかれ許容され要求のタイムアウトを数時間に増やしてください(!)。しかし、私は依然として、メッセージのキューへの送信を遅くするより効果的な方法を探しています。サーバ。

提案がありますか? 待ち行列のサイズをさらに増やすことの結果について考えてみましょうか?

+3

私は処理しているデータの量を減らす方法を探しています。 –

+0

@DanBracukそれはもちろん、最適だろう。しかし、処理するデータの量は実際には交渉可能ではありません...私はそれをカットしようとする可能性がありますが、私がやろうとしている主なことは、 – Sander

+0

本当に 'gatewayService'を変更できない場合は、ここではあまりできません。あなたは ' 'に変更することができますが、それは大きな違いがあるとは思えません –

答えて

1

現時点では、アプリケーション変数を使用して、ジョブ全体のレコード、すでに処理されたバッチの数、処理されたレコードの数を追跡します。

<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> 

その後、私は、クエリ内のすべてのレコードを設定し、我々がする必要があることをクエリでレコードを決定します。ジョブの開始時に は、私はすべてのこれらのそうのような変数を開始したコードの一部を持っています現在のバッチのプロセスです。 バッチ内のレコードの量は、レコードの総量と最大キューサイズによって決まります。この方法では、各バッチは決してキューの約半分を占めることはありません。これにより、ジョブが他の操作やジョブに干渉することがなく、最初の要求がタイムアウトしないことが保証されます。

<cfset application.recordsToSync = qryRecords.recordcount> 
<cfif not structKeyExists(application,"recordsPerBatch") or application.recordsPerBatch eq "" or application.recordsPerBatch eq 0> 
    <cfset application.recordsPerBatch = ceiling(application.recordsToDo/(ceiling(application.recordsToDo/gatewayService.getMaxQueueSize())+1))> 
</cfif> 
<cfset startRow = (application.recordsPerBatch*application.batchNumber)+1> 
<cfset endRow = startRow + application.recordsPerBatch-1> 
<cfif endRow gt application.recordsToDo> 
    <cfset endRow = application.recordsToDo> 
</cfif> 

次に、from/toループを使用してクエリをループして、ゲートウェイイベントを起動します。私は、キューがいっぱいであるためレコードが失われないようにガーディアンを守った。

<cfloop from="#startRow#" to="#endRow#" index="i"> 
    <cfset guardianCount = 0> 
    <!--- load all values from the record into a struct ---> 
    <cfset stRecordData = structNew()> 
    <cfloop list="#qryRecords.columnlist#" index="columnlabel"> 
     <cfset stRecordData[columnlabel] = trim(qryRecords[columnlabel][i])> 
    </cfloop> 
    <cfset eventData = structNew()> 
    <cfset eventData.stData = stRecordData> 
    <cfset eventData.action = "bigJob"> 
    <cfloop condition="#gatewayService.getQueueSize()# GTE #gatewayService.getMaxQueueSize()#"> 
     <cfset guardianCount = guardianCount++> 
    </cfloop> 
    <cfset SendGatewayMessage("eventGateway",eventData)> 
</cfloop> 

レコードが完了するたびに、実行するレコードの数と実行するレコードの数をチェックする機能があります。彼らが同じとき、私はやっています。それ以外の場合は、新しいバッチを開始する必要があります。 完了したかどうかのチェックはcflockにありますが、実際のイベント投稿はcflockではないことに注意してください。これは、投稿したイベントがロック内で使用する変数を読み取れない場合に、デッドロックが発生する可能性があるからです。

私はこれが誰かや他の人には役に立つと思っています。

<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では、この種のバッチ処理はdb駆動型であるため、現在のバッチ、つまりXレコードに必要なデータのみをプルし、アプリケーションが再起動しても最後の既知の状態が維持されます。 – Leigh

関連する問題