2

我已经构建了一个 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>
4

2 回答 2

1

请记住,coldfusion 中的线程受服务器版本的限制——我认为标准版最多支持 10 个线程——其他线程排队。向线程提供“回调”将完成这项工作。在 sql 转储完成后,还可以利用计划任务。

于 2017-11-03T17:46:27.960 回答
1

听起来你只需要调用者提供的回调。

  1. 接受请求,包括一个外部 URL,供您的代码在完成后点击
  2. 开始线程,不加入
  3. 向调用者返回正在处理请求的信息,结束主请求
  4. 线程继续运行并最终点击回调 url,提供有关成功或失败的任何附加信息

这里还提供了一些其他选项。首先,您可以只接受并将请求所需的数据记录在队列中,然后稍后再点击它们。此外,正如您所说,您可以为调用者提供状态端点以检查进度。

于 2017-11-03T13:56:33.793 回答