Lucee/Adobe ColdFusion - Setting/getting 来自线程的信息{}

Lucee/Adobe ColdFusion - Setting/getting information from thread{}

我正在创建一个调用两个不同 CFC 的简单电子邮件服务器状态页面。

状态页要求:

  1. 通过 CFC 查询 MariaDB 数据库 table 和来自两个字段的 return 数据:server_name(即 MyServerName)和 server_domain(即 mail.domain.com).目前,数据库中有 4 行 table 可以拉取。
  2. 将第 1 步中的数据库数据交给检查端口 25 是否正在侦听的 CFC。如果 CFC 可以到达端口 25,则结果为真,否则结果为假。这一步需要穿线。
  3. 通过循环处理步骤 2 的布尔结果以打印 server_name 和布尔结果。

输出类似这样的东西:
我的服务器名称 - <up arrow>
我的服务器名称 2 - <up arrow>
我的服务器名称 3 - <up arrow>
我的服务器名称 4 - <down arrow>

代码:

    RetrieveEmailServers = APPLICATION.selectQueries.RetrieveEmailServers()
    if (RetrieveEmailServers.recordCount) {
        for(i = 1; i <= RetrieveEmailServers.recordCount(); i++) {
            LOCAL.theDomains = RetrieveEmailServers.check_servers_domain[i];
            LOCAL.theNames = RetrieveEmailServers.check_servers_name[i];
            thread action="run" name="thread#i#" theDomains="#LOCAL.theDomains#" theNames="#LOCAL.theNames#" {
                VARIABLES.theServers = APPLICATION.emailCheck.checkSMTPServer('#domains#',25,'','');
            }
        }
        thread action="join" timeout="6000"{}

        for(i = 1; i <= RetrieveEmailServers.recordCount(); i++) {
            VARIABLES.theResult = cfthread["thread#i#"];
            if (VARIABLES.theResult.theServers) {
                LOCAL.theStatus = "<i class='fad fa-angle-double-up text-success fs-1'></i>"
            }
            else {
                LOCAL.theStatus = "<i class='fad fa-angle-double-down text-danger fs-1'></i>"
            } 
            writeOutput(ATTRIBUTES.theNames & " - " & LOCAL.theStatus & "<br>");
        }
    }
    else {
        writeOutput("No servers listed at this time.")
    }

错误:键[THESERVERS]不存在,结构为空

供考虑:

  1. 我知道我的代码不是很好而且我知道它可以写得更好。我正在努力提高。
  2. 我不是全职编码员,但我断断续续地编码了很多次 年。我仍然认为自己是 CFML 的新手,所以很多方法都让我头疼。
  3. 上面的代码大部分都有效,但我理解起来有困难 如何将信息传递到 CFTHREAD 之外以供其余使用 页面,尤其是在处理 CFLOOP 时。
  4. 看了很多遍,还是没完全看懂,怎么办 正确使用线程局部作用域、线程作用域和 属性范围。
  5. 上面的代码有一个简单的任务,即检查一个端口,但最终目标是为我的应用程序的其他部分使用类似的代码。我知道有更好的监控工具可用;这是一个帮助我理解和学习的练习。
  6. 特定于 Lucee,我知道 threadData()['thread#i#'].status; 或类似内容可能需要对 cfthread[] 进行修改。

属性

Attributes 作用域仅用于保存传递给 线程的值。因此,作用域是短暂的,只存在于一个线程内。每个线程都有自己的“属性”范围,在该线程运行之前或完成之后不存在。

例如,此代码段传入名为“theDomains”的属性。变量 Attributes.theDomains 仅存在于 内部 线程。

 thread action="run" name="thread1" theDomains="example.com" {
     writeDump( attributes.theDomains );
 }
 
 thread action="join" name="thread1" {};
 
 writeOutput( thread1.output );

本地线程

“Thread-local”是另一个短暂的作用域,其目的是保存在一个线程中使用的变量。每个线程都有自己的私有“本地”范围,与所有其他线程分开。与 attributes 范围一样,它仅在线程执行时存在,并在线程完成时消失。

例如,此代码段创建了一个名为“MyLocalVar”的局部变量。显示线程 output 表明线程中存在变量

thread action="run" name="thread1" {
    // Un-scoped v
    myLocalVar = "foo";
    writeOutput( "myLocalVar ="& myLocalVar );
}

thread action="join" name="thread1" {};
writeOutput( thread1.output );

但是在线程完成后尝试访问它会导致错误

// fails with error "key [MYLOCALVAR] doesn't exist"
writeOutput( "myLocalVar ="& thread1.myLocalVar );

Thread 范围

Thread 瞄准镜的使用寿命更长。它旨在存储 "..thread-specific variables and metadata about the thread..."。更重要的是,这个范围可用于将信息传回调用页面(甚至其他线程)。

例如,此代码段创建了一个对调用页面可见的线程范围变量,即使在线程完成执行后也是如此:

 thread action="run" name="thread1" {
    // use scope prefix "thread."
    thread.myThreadVar = "foo";
 }
 
 thread action="join" name="thread1" {};
 
 writeOutput( "thread1.myThreadVar="& thread1.myThreadVar );
 writeDump( thread1 );

问题:密钥 [THESERVERS] 不存在

当您几天来一直在查看错误时,很容易忘记基本知识 :) 处理未定义错误的第一件事是转储对象并查看 实际上 包含您在尝试使用它之前所期望的内容。

for(i = 1; i <= RetrieveEmailServers.recordCount(); i++) {
    VARIABLES.theResult = cfthread["thread#i#"];
    writeDump( variables.theResult );

    /* temporarily comment out rest of code 
    ...
    */
}

VARIABLES.theResult 的转储显示线程实际上因不同的错误而失败

由于线程内的属性名称错误。应该是attributes.theDomains,不是domains.

thread ...{
    APPLICATION.emailCheck.checkSMTPServer( attributes.theDomains, ... );
}

好的,我修好了。仍然收到“密钥 [THESERVERS] 不存在”,现在怎么办?

线程的另一个转储表明错误消息没有说谎。由于范围界定不正确,线程实际上不包含名为 theServers 的变量。使用 thread 作用域,而不是`变量。

 thread ...{
     thread.theServers = ....;
 }

又一个错误?!变量 [ATTRIBUTES] 不存在

即使解决了前两个问题,您仍然会在这里遇到另一个错误

for(i = 1; i <= RetrieveEmailServers.recordCount(); i++) {
   ...
   writeOutput(ATTRIBUTES.theNames & " - " & LOCAL.theStatus & "<br>");
}

记住 attributes 作用域只存在于一个线程中。所以显然一旦线程完成就不能使用了。也可以将 theNames 存储在 thread 范围内,或者由于您正在循环查询,请使用查询列值 RetrieveEmailServers.the_query_column_name[ i ].

加入线程

最后一个潜在问题。 join 语句实际上并不是在等待您创建的线程。它只是在等待 6000 毫秒。如果出于某种原因,任何线程花费的时间超过该时间,您将在尝试检索线程结果时收到错误消息。要真正等待创建的线程,您必须使用 thread action="join" name=(list of thread names) {}。我将把它留作 reader (:

Tbh,还有其他可以清理的东西 and/or 改进了,但希望这个冗长的杂乱无章的线程首先解释了为什么会出现错误以及如何在工作时避免这些错误未来有线程