2016-11-03 2 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 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