p:commandButton ajax + BlockUI/GraphicImage 微调器 - 一分钟后超时

p:commandButton ajax + BlockUI/GraphicImage spinner - timing out after a minute

提问人:java_hacker_guy123 提问时间:6/30/2023 最后编辑:Jasper de Vriesjava_hacker_guy123 更新时间:6/30/2023 访问量:44

问:

PrimeFaces 6.1、WildFly 8.1.0、OmniFaces 版本 2.7

我正在开发一个应用程序,该应用程序基本上允许我公司的人提交员工培训认证请求,并将其提交到后端表中进行进一步处理。我有一个结构如下的表格:

<h:form id="classRequestForm">       
                    <p:panel header="Select Certification" style="width: 475px;  margin: 4px;">
 
                        <p:panelGrid columns="2" style="margin-bottom: 10px">
                            <h:panelGroup>       
                                        <h:panelGrid> 
                                            <h:outputLabel value="Certification Title(s) (Limit: 5)" />                                 
                                            <p:autoComplete id="autoCertSearch" value="#{trainingAlterView.certRequestList}" queryDelay="100" maxResults="30"
                                                styleClass="courseMultiAutoComplete" completeMethod="#{certificationListAutoComplete.getByKeywords2}"
                                                var="certSelect"  panelStyle="width: 500px !important;"
                                                converter="#{certConverter}" requiredMessage="Cert Required" itemValue="#{certSelect}"
                                                emptyMessage="No Matches!" itemLabel="#{certSelect.certTitle}"
                                                title="Start typing Cert Title" selectLimit="5" forceSelection="true" minQueryLength="3"
                                                scrollHeight="300" multiple="true">

                                                <p:column headerText="Title" style="width: 500px">
                                                    <h:outputText value="#{certSelect.certTitle}" />
                                                </p:column>
                                                <p:column headerText="Type">
                                                    <h:outputText value="#{certSelect.certFamily}" />
                                                </p:column>  
                                        <p:ajax event="itemSelect" delay="100" listener="#{trainingAlterView.certListRefresh}" />  
                                        <p:ajax event="itemUnselect" delay="100" listener="#{trainingAlterView.certListRefresh}" /> 
                                        <p:ajax event="valueChange" delay="100" listener="#{trainingAlterView.certListRefresh}" /> 
                                        <p:ajax event="change" delay="100" listener="#{trainingAlterView.certListRefresh}" />   
                                    </p:autoComplete>
                                        
                                            <p:watermark for="autoCertSearch" value="Start typing Cert Title"
                                                onclick="PrimeFaces.cleanWatermarks();" oncomplete="PrimeFaces.showWatermarks();" />
        
                                        </h:panelGrid>                           
                                        <p style="margin:0;padding:0;text-align:right;"> 

                                            <p:commandLink
                                                action="#{trainingAlterView.certListRefresh}" update="tarSelectForm" process="@this" partialSubmit="true"
                                                style="color:#00f;text-decoration:underline; text-align:right;margin-top: 10px;" value="View Training Assignment Summary..." oncomplete="PF('errorArea2').show();"> 

                                            </p:commandLink> 
                                        </p>
                            </h:panelGroup>
                            
                             
                            

                        </p:panelGrid>

                    </p:panel> 

                    <p:panel header="Add Employee(s)" style="width: 475px;  margin: 4px;">

                    
                        <p:panelGrid columns="2" style="margin-bottom: 10px">
                            <h:panelGroup>
                                <h:panelGrid>
                                    <h:outputLabel value="Employee" />
                                    <p:autoComplete size="55" id="employeeToSearch" value="#{trainingAlterView.personList}" queryDelay="100" maxResults="30"
                                        styleClass="empMultiAutoComplete" converter="#{personConverter}" required="true"
                                        requiredMessage="Employee Required" panelStyle="width: 500px !important;"
                                        completeMethod="#{personListAutoComplete.getByKeywords2}" var="person" itemValue="#{person}"
                                        emptyMessage="No Matches!" itemLabel="#{person.fullName} (Badge: #{person.personId}, Shift: #{person.shift}, Dept: #{person.dept})" forceSelection="true" minQueryLength="3"
                                        scrollHeight="300" multiple="true" 
                                        placeholder="Start typing Emp Name">

                                         
                                        <p:column headerText="Id" style="width: 5px;">
                                            <h:outputText value="#{person.personId}" />
                                        </p:column>
                                        <p:column headerText="Name" style="width: 100px;">
                                            <h:outputText value="#{person.fullName}" />
                                        </p:column>
                                        <p:column headerText="Shift" style="width: 5px;">
                                            <h:outputText value="#{person.shift}" />
                                        </p:column>
                                        <p:column headerText="Dept/Div" style="width: 10px;">
                                            <h:outputText value="#{person.dept}" />
                                        </p:column>
                                        <p:column  headerText="MSS Supervisor Badge" style="width: 100px">
                                            <h:outputText value="#{person.supervisorId}" />
                                        </p:column> 
                                        <p:column  headerText="ATA Supervisor Badge" style="width: 100px">
                                            <h:outputText value="#{person.ataSupervisorId}" />
                                        </p:column>  

                                        <p:ajax event="itemSelect" delay="100" listener="#{trainingAlterView.persListRefresh}" />  
                                        <p:ajax event="itemUnselect" delay="100" listener="#{trainingAlterView.persListRefresh}" /> 
                                        <p:ajax event="valueChange" delay="100" listener="#{trainingAlterView.persListRefresh}" /> 
                                        <p:ajax event="change" delay="100" listener="#{trainingAlterView.persListRefresh}" />    
                                
                                    </p:autoComplete>
                                                                          
                                    
                                </h:panelGrid>
        
                    
                            </h:panelGroup>
                            
                            <p:commandButton style="margin-top: 10px;" value="All Personnel" onclick="PF('rosterQuickAddDialog').show(); return false" /> 

                        </p:panelGrid>
                    
                    </p:panel>
    
                    <p:panel header="Justification" style="width: 475px;  margin: 4px;">
                        <p:panelGrid columns="2" style="margin-bottom: 10px">
                            <p:outputLabel for="justification" value="Category:" />
                            <p:selectOneMenu value="#{trainingAlterView.justification}" id="justification" style="width:275px" required="true" requiredMessage="Justification Required">       
                                <f:selectItem itemLabel="Select One" itemValue="" />
                                <f:selectItem itemLabel="Apprentice Program" itemValue="Apprentice Program" />
                                
                                <f:selectItem itemLabel="Attrition - Employee retiring" itemValue="Attrition - Employee retiring" />
                                <f:selectItem itemLabel="Attrition - Employee changing shift within the same department" itemValue="Attrition - Employee changing shift within the same department" />
                                <f:selectItem itemLabel="Attrition - Employee changing department" itemValue="Attrition - Employee changing department" />
                                <f:selectItem itemLabel="Attrition - Employee changing supervisor within the same department on the same shift" itemValue="Attrition - Employee changing supervisor within the same department on the same shift" />
                                </p:selectOneMenu>
                        </p:panelGrid>

                        <p:panelGrid columns="2" style="margin-bottom: 10px;">
                            <p:outputLabel for="comments" value="Detailed Summary:" />
                            
                              <p:inputTextarea requiredMessage="Summary Required" value="#{trainingAlterView.comments}" placeholder="E.g., An employee retired and we need to train a new employee to perform a similar task." style="width:310px" id="comments" rows="5" cols="30" required="true" maxlength="4000"  autoResize="false" />
                        </p:panelGrid>
                    </p:panel>

            <p:commandButton id="submit" update=":classRequestForm:employeeToSearch :classRequestForm:justification :classRequestForm:comments" style="margin-top: 3px; margin-right: 10px;" ajax="true" value="Request Certification(s)" action="#{trainingAlterView.addCertRequest2}" />   
                      
            <p:button style="margin-top: 3px; margin-right: 10px;" value="Reset" ajax="false" type="reset" />        
                     
                         
                        <p:blockUI block="classRequestForm" trigger="submit">
                            <p:graphicImage name="gfx/ajax-loader.gif" />
                        </p:blockUI>
</h:form>

当单击“submit”commandButton时,它会触发如下所示的函数(省略了很多代码,但这是基本思想):

public void addCertRequest2() {  
        
        RequestContext context = RequestContext.getCurrentInstance();
 

        Boolean hasDeptAdmin  = null;
        Boolean hasDeptMgr    = null;
        Boolean hasSupervisor = null; 
        Boolean isContractor = false;
        String providerString = null;  
        String ccs = null;
        Integer managerLevel           = null;
        Boolean mgr_check              = false;
        Integer supervisor_mgr_level   = null;
        List<LearningObject> subCertDetail = null;
        List<LearningObject> assignedItems = null;
        List<String> assignedItemsCertIds = new ArrayList<>();
        List<String> certRequestListIds = new ArrayList<String>(); 
        List<TrainingAlterRequest> pendingRequests = null;
        List<String> rosterBadgeList = new ArrayList<String>();
        Set<String> dupResultArr = null; 

        for(int j = 0; j < personList.size(); j++) {
            rosterBadgeList.add(0, personList.get(j).getPersonId()); 
        }  
        

        for(int c=0; c < certRequestList.size(); c++) {
            certRequestListIds.add(0, certRequestList.get(c).getCertId());  
        } 

        for(int certLoop=0; certLoop<certRequestList.size(); certLoop++) { 
            [...]
                         for(int k=0; k<personList.size(); k++)
                                
                             // nested loop that does additional processing/duplicate checks/etc.
                         }
            switch(...) {
                [...]
            }
        }

        
        [Hibernate/DB calls...] 
        [Hide form]
        [Messages.addAjaxMessage success messages]
    return;
     }

该功能完全符合我的要求并且运行良好 - 例如,当为或 5 名员工申请一到两个认证时(总共请求了 5-10 个认证)。

但是,如果我尝试为 5-10 名员工(发起 25-50 个请求)申请 5 个认证(目前表格上的最大值),则可能需要几分钟(3-5 分钟)。大约一分钟(60 秒)后,BlockUI/ajax 微调器突然消失,表单中的所有信息都保留了下来,但代码似乎仍在后台成功处理(即,请求被提交到后端数据库)。

日志中未显示任何错误。这非常令人沮丧和困惑,我只是不确定发生了什么。我尝试将以下内容添加到我的commandButton中:

<p:commandButton timeout="750000" ...

但无济于事。(还有其他各种超时值,但没有任何效果。

为什么它似乎只是停止了这个功能:

  <p:blockUI block="classRequestForm" trigger="submit">
                            <p:graphicImage name="gfx/ajax-loader.gif" />
                        </p:blockUI>

一分钟后?有没有办法确保它运行(即,表单被 BlockUI 阻止并且 Ajax 加载/微调轮继续显示)直到代码完成处理?我还有一些addAjaxMessage()成功消息,在完成处理时显示和“PF().hide()”表单,但是,就像我说的,一分钟后表单上的BlockUI“阴影”消失了,ajax-loader.gif微调器消失了。表单中留下了信息,并且永远不会显示成功消息,并且用户对它是否有效感到困惑,这是不可接受的。

伙计们对此有什么想法吗?非常感谢。

Ajax JSF Primefaces

评论

1赞 Jasper de Vries 6/30/2023
请求可能会超时。在后端工作时,最好使用 websockets 和 JMS,这比您的平均请求花费更长的时间。PrimeFaces 6 真的很老了。从那以后,BlockUI已经看到了一些改进。
0赞 Melloware 7/4/2023
是的,您的 HTTP 请求可能在 60 秒时超时,并且还提到了自 6.1 以来 PF 的许多改进

答: 暂无答案