2

我希望有人可以帮助我解决我们目前面临的一个非常严重的问题,即当用户在其中工作时,关键业务应用程序会丢失数据。

这是随机发生的——我从未复制过,但系统中的用户比我多得多。

创建了一个文档,上面有很多字段,并且有 2 个富文本字段。我们使用的是 Domino 8.5.3 - 没有使用扩展库控件。该文档内置了工作流,所有验证都由从数据查询保存事件调用的 SSJS 函数完成。sessionscope.log 有大量的日志记录,并且(现在)在笔记文档中为每个用户捕获了这些记录,因此我可以查看他们在做什么。

有时,用户进入工作流程步骤,他们必须填写富文本字段并在下拉字段中做出选择,然后他们使用工作流程按钮提交文档。当按下工作流按钮(进行完整更新)时,一些客户端 JS 首先运行

// Process any autogenerated submit listeners
if( XSP._processListeners ){ // Not sure if this is valid in all versions of XPages
    XSP._processListeners( XSP.querySubmitListeners, document.forms[0].id );
}

(我添加这个是为了防止 RTF 字段在阅读博客后丢失它们的值,但到目前为止它不起作用)

然后服务器端事件运行并调用 view.save() 以触发 QS 代码(用于验证)和 PS 代码以在服务器上运行工作流代理。

95%的时间,这工作正常。

但是,有 5% 的时间,页面会刷新对 RFT 字段 (CKEditor) 和下拉字段所做的所有更改,都像以前一样重新加载,没有内容。就像保存没有发生一样,完全更新按钮决定像页面刷新而不是提交一样工作。

在正常情况下,日志显示当按下工作流按钮时,QuerySave 代码启动并返回 True。然后记录按下的工作流按钮的 ID(这样我可以在查看问题时看到正在使用哪些按钮),然后 PostSave 代码开始并最终返回 true。

出现问题时,QuerySave 事件运行,如果验证通过则返回 true,如果验证失败则返回 false,然后停止。工作流按钮的 ID 也会被记录下来。但是如果 QuerySave 返回 true,代码应该继续调用 PostSave 函数——它甚至不会记录它正在启动 PostSave 函数。

更糟糕的是,在调用 PostSave 代码失败后,记录的下一件事是运行的 beforePageLoad 事件,这显然会重新加载页面,该页面没有最近的编辑,因此用户失去了所有他们输入的信息!

这一定是我在使用 XPages 时遇到过的最烦人的问题,因为我找不到成功的 QuerySave(甚至因为未填写必填字段而导致失败)会导致页面像这样刷新并丢失内容。请有人可以帮我指出正确的方向吗?

4

4 回答 4

1

听起来好像在 5% 的用例中,文档打开超过 30 分钟并且 XSP 会话超时 - 提交导致重新创建组件树,并且现在空页面返回给用户。尝试增加应用程序的超时时间以查看问题是否消失。

于 2012-05-31T14:54:27.270 回答
0

My experience is that this problem is due to keeping page in memory. Sometimes for some reason the page gets wiped out of memory. I'm seeing this when there is a lot of partial refreshes with rather complex backend Java processing. This processing somehow seems to take the space from memory that is used by the XPage.

The problem might have been fixed in later releases but I'm seeing it at least in 8.5.2.

In your case I would figure out some other workaround for the CKEditor bug and use "Keep pages on disk" option. Or if you can upgrade to 9.0.1 it might fix both problems.

于 2013-11-07T14:02:03.897 回答
0

我会设计流程略有不同。在 JSF/XPages 中,验证属于验证器,而不属于 QuerySave 事件。另外我宁愿对按钮使用提交,因此您不需要在代码中触发 view.save() 。这不会干扰 JSF 的一系列事情 - 但这种风格不一定是你问题的根源......关于这个的想法:

正如 Jeremy 一样,我首先会怀疑超时,然后下一站是 QuerySave 事件中的一个致命问题,它会破坏运行时(无论出于何种原因)。你可以尝试这样的事情:

var qsResult = false;
// your code goes here, no return statements
// please and if you are happy
qsResult = true;
return qsResult;

悲观的方法最终会告诉你是否有问题。另外:如果发生中止并且您的 querySave 刚刚返回,那么您可能会在这个陷阱中运行

function noReturn() {return; }  //nothing comes back!

noReturn() == true;    --> false
noReturn() == false;   --> false
noReturn() != false;   --> true!!!!

您需要检查的内容:您的性能设置是什么:序列化到磁盘、保存在内存中还是保存在内存中?可能是您违反了 JavaScript 库的工作方式。

SSJS 库在需要时加载。里面的变量被初始化。当内存条件需要时,库会被卸载,并且所有相关的变量都会被丢弃。因此,如果您在调用之间依赖位于 SSJS 库中的 JS 函数中的任何变量,您可能会或可能不会取回该值,这可能会描述您的错误情况。你想保留的东西应该进入一个范围(viewScope 似乎就在这里)。

让它更棘手一点:当您使用闭包和第一类函数时,这些函数可以访问父函数的变量,除非库已被卸载。此外,函数(您也可以将它们停放在作用域中)不会序列化(开放缺陷),因此在将它们放入作用域时需要小心。

如果你的东西真的很复杂,你可能会更好地使用 backing bean。那有帮助吗?

于 2012-05-31T16:54:57.093 回答
0

要创建托管 bean(或更多),请查看Per 的文章。您的验证器将位于应用程序 bean 中:

<faces-config>
    <managed-bean>
       <managed-bean-name>workflowvalidator</managed-bean-name>
       <managed-bean-class>com.company.WfValidator</managed-bean-class>
       <managed-bean-scope>application</managed-bean-scope>
    </managed-bean>
</faces-config>

在内部,您将使用地图来显示错误消息

public Map<String,String> getErrorMessages() {
     if (this.errorStrings == null) { // errorStrings implements the MAP interface
        this.loadErrorDefinitions(); //Private method, loads from Domino
     }
     return this.errorStrings;
}

那么您可以在验证器的错误消息字符串中使用 EL:

 workflowvalidator.errorMessage("some-id");

这允许 XPages 直接在 EL 中选择正确的,这比 SSJS 更快。然后,您可以去实现您自己的与该 bean 对话的自定义 Java 验证器(这将允许您在此处绕过 SSJS)。除了示例之外,我不会将注释代码放入其中,而是与您的 WfValidator 类交谈。为此,您需要在 Java 中处理它:

private WfValidator getValidatorBean() {
    FacesContext fc = FacesContext.getCurrentInstance();
    return (WfValidator) fc.getApplication()
                           .getVariableResolver()
                           .resolveVariable(fc, "workflowvalidator");
}

使用解析器,您可以访问加载的 bean。希望有帮助!

于 2012-06-02T16:29:14.860 回答