Обрабатывать внешний HTTP-запрос с помощью CFTHREAD и возвращать асинхронный ответ

Я создал API, где внешний сервер может публиковать данные JSON на наш сервер ColdFusion. Сервер ColdFusion затем обрабатывает эти данные (перебирает массивы и вставляет данные в базу данных и т. Д.), А затем отвечает внешнему серверу, что все прошло нормально или нет.

Но я бы предпочел запустить процесс в CFTHREAD, потому что в будущем нагрузка станет более тяжелой. Как я могу выполнить этот вид асинхронного действия и по-прежнему отвечать на сервер, который сделал запрос?

Я посмотрел на шлюзы событий, но, похоже, это не тот путь. Я также думал о том, чтобы позволить внешнему серверу выполнять повторяющиеся вызовы, такие как "ты уже сделал", "ты уже сделал", но это не похоже на окончательное решение.

Я могу заставить ребят, управляющих внешним сервером, называть наш сервер ColdFusion так, как мы хотим, так что, по крайней мере, я не связан этим.

Вот упрощенная версия моего index.cfm, который получает вызов:

<cftry>
  <cfinclude template="udf.cfm" />
  <cfset _run()>
  <cfcatch type="any">
    <cfcontent type="application/json; charset=utf-8" reset="yes">
    <cfoutput>{"success":0,"message":"#cfcatch.Message# - #cfcatch.Detail#"}</cfoutput>
  </cfcatch>
</cftry>

А вот мой udf.cfm, который обрабатывает вызов (опять-таки упрощенная версия):

<cffunction name="_run" output="yes" returntype="void">
    <cfset local.success=true>
    <cfset local.msg="">
    <cftry>
        <!---get request data--->
        <cfset local.requestData=GetHttpRequestData()>
        <!---validate post--->
        <cfif NOT StructKeyExists(local.requestData,"headers")>
            <!---headers is missing--->
            <cfset _returnJson(msg="Headers is missing")>
        </cfif>
        <!---and a bunch of other validations...--->
        <!---get body--->
        <cfset local.isBinaryBody=IsBinary(local.requestData.content)>
        <cfset local.bodyAsString=local.isBinaryBody ? ToString(local.requestData.content) : local.requestData.content>
        <cfset local.body=DeserializeJson(local.bodyAsString)>
        <cftransaction action="begin">
            <cftry>
                <!---prepare for database inserts by cleansing tables etc--->
                <!---loop data array, can be tens of thousands of rows--->
                <cfloop array="#local.body.items#" index="local.item">
                    <!---do some inserts/updates into MySQL Database--->
                </cfloop>
                <cfcatch type="any">
                    <!---error--->
                    <cfset local.msg=_parseCatchError(catch=cfcatch)>
                    <cfset local.success=false>
                </cfcatch>
            </cftry>
            <!---rollback or commit transaction depending on success flag--->
            <cftransaction action="#local.success ? 'commit' : 'rollback'#" />
        </cftransaction>
        <cfcatch type="any">
            <!---error--->
            <cfset local.msg=_parseCatchError(catch=cfcatch)>
            <cfset local.success=false>
        </cfcatch>
    </cftry>
    <!---return JSON--->
    <cfset _returnJson(msg=local.msg,success=local.success)>
</cffunction>
<cffunction name="_returnJson" output="yes" returntype="void">
    <cfargument name="msg" type="string" required="yes">
    <cfargument name="success" type="boolean" default="false">
    <cfscript>getPageContext().getOut().clearBuffer();</cfscript>
    <cfcontent type="application/json; charset=utf-8" reset="yes">
    <cfoutput>#SerializeJson(arguments)#</cfoutput>
    <cfabort>
</cffunction>
<cffunction name="_parseCatchError" output="no" returntype="string">
    <cfargument name="catch" type="any" required="yes">
    <cfset local.error="#Trim(arguments.catch.message)# - #Trim(arguments.catch.detail)#">
    <cfif StructKeyExists(arguments.catch,"tagContext")>
        <!---grab line info--->
        <cfset local.tagContext=arguments.catch.tagContext[1]>
        <cfset local.error=local.error&" - #Trim(local.tagContext.template)# line #Trim(local.tagContext.line)#">
    </cfif>
    <cfreturn local.error>
</cffunction>

2 ответа

Решение

Похоже, вам просто нужен обратный звонок, предоставленный абонентом.

  1. принять запрос, в том числе внешний URL для вашего кода, чтобы поразить после завершения
  2. начать тему, не присоединяйтесь
  3. вернуть информацию вызывающей стороне о том, что запрос обрабатывается, завершив основной запрос
  4. поток продолжает работать и, в конце концов, нажал на URL обратного вызова, предоставив любую дополнительную информацию об успехе или неудаче

Несколько других вариантов также доступны здесь. Прежде всего, вы можете просто принять и записать данные, необходимые для запроса, в очередь, а затем отправить их позже. Кроме того, как вы заявили, вы можете предоставить конечную точку состояния для вызывающей стороны для проверки хода выполнения.

Имейте в виду, что потоки в Coldfusion ограничены версией сервера - я думаю, что стандартная версия поддерживает до 10 потоков - другие идут в очередь. Предоставление "обратного вызова" потоку сделает работу. Также запланированные задачи могут быть использованы после завершения дампов sql.

Другие вопросы по тегам