Debugging Zen Assertions

265 views
Skip to first unread message

Dawn Wolthuis

unread,
Dec 5, 2008, 3:25:10 PM12/5/08
to InterSystems: Zen Community
I just had another dreaded Zen assertion error, actually two: both
"thread id should be null" (which I cannot find when searching %SYS,
even causes Studio to abort when I search for it) and "refresh list
should not be null." I'm starting to do what another team member does
and throw up my hands instead of going through the painful work of
trying to figure these out. At best we end up with these going away
for no known reason after we change things around enough (randomly, of
course ;-) rarely able to pinpoint precisely what fixed it in spite of
our efforts to do so. These do not seem to affect the integrity of the
system from a data perspective, but obviously severely affect the user
experience (show-stopper for that), so we have to address.

I know I've asked this before, but I am still clueless. Could anyone
explain just what these errors are and when they show up? What are
they trying to tell us? Where can we get more information about them
-- a stack trace, perhaps? What typically causes them? What is the
best way to debug them (firebug? alerts often don't help a lot as it
is often with asynch stuff)? Bottom line -- how do we get these to go
away? This might be inaccurate, but I think that one time a zen
assertion error went away when we fixed a javascript syntax error and
another went away when we switched to running something synchronously
IIRC.

Are we the only ones who get these regularly? I suspect we are
missing some key concept that causes us to hit these regularly,
typically causing hours of lost work and a general decline in our
spirits.

If no one has any answers on this, perhaps just send out a limerick or
something else to help me keep smiling. thanks. --dawn
--
Dawn M. Wolthuis

Take and give some delight today

Derek Day

unread,
Dec 5, 2008, 3:34:03 PM12/5/08
to InterSys...@googlegroups.com
Hi, Dawn.

The following should probably be an article -- lets discuss it and then
based on the discussion, I will post an edited version if that seems
useful. This document should incorporate all the information from
previous posts on this question. Your recollection is correct and the
two solutions that you have used before are explained more fully here.

The short answer is that it is not /always/ your fault when you receive
this message! The medium sized answer is that you should be getting this
message a lot more often using the current mechanism and the long
answer, well, the long answer is below.
================================================================
The 'refresh list should not be null' assertion occurs after
synchronizing the DOM on the client in
the call to zenEndDeferredRefresh. The 'refresh list' is a set of
changes to the DOM shipped to the
client. zenEndDeferredRefresh() signals the client-side objects to
redraw themselves based on the
changes from the client. This allows Zen to only redraw the page once
per 'refresh'.

The generated synchronization code looks something like this:
// %EndChangeTracking: sync client with server changes

try {

zenBeginDeferredRefresh('2','%ZEN.Component.tablePane.ReallyRefreshContents');

var o = zenPage.getComponent(27); //5@%ZEN.Component.tablePane

if (o) {

o.setProperty('lastUpdate','2008-11-26 19:15:36.357');

o.rowCount = '8';

o.snapshotId = 31600518;

o.fireOnUpdateEvent();

}

zenEndDeferredRefresh('2','%ZEN.Component.tablePane.ReallyRefreshContents');

}

catch(ex) {

zenExceptionHandler(ex,arguments,'A JavaScript error occurred in
%EndChangeTracking.');

zenEndDeferredRefresh('2','%ZEN.Component.tablePane.ReallyRefreshContents');

}

You will note that there are two ways for zenEndDeferredRefresh() to be
called, when the
synchronization completes successfully, and when an exception is thrown.

This leads to the first case where the assertion failure can happen:
If an exception is thrown in zenBeginDeferredRefresh() or
in the synchronization code itself.
To resolve this, it is necessary to use a tool such as FireBug for
FireFox to view the response
from the server. Alternatively, WireShark(wireshark.org) or tcptrace
(www.pocketsoap.com/tcptrace/) may
be used to capture the messages. It is generally obvious based on the
code sent to the browser
whether this is the problem.

The 'refresh list' is initialized in zenBeginDeferredRefresh() and is
cleared in
zenEndDeferredRefresh; so if zenEndDeferredRefresh() is called twice
during one refresh cycle (aka ZenMethod call),
then the second time through it will see the assertion failure. This
usually happens when. as a result
of one ZenMethod call, a user callback is invoked which makes a second
ZenMethod call; this causes
the deferred refreshes to be nested.

There is a mechanism which is supposed to stack these nested calls to
properly handle this case,
however we have recently discovered that this mechanism does not fully work.
[NOTE: In some cases this situation is due to
programmer error and the DOM synchronizations
could be incompatible. In most cases this is
fine, though not very efficient.]

To resolve this there are three basic strategies. The first, is to look
at the network or trace
messages and to eliminate any logic errors and try to remove multiple
trips to the server.

The second strategy, which can make the code more efficient as well, is
to detect callbacks which
are generated because of the refresh. For example, the tablePane
component has a rowChanged event
callback which is sent a reason code, programmatic row change events
(such as a refresh) have a reason
code of "" and therefore do not require the same actions to be run as
when the row change event was
triggered by the user.

The third stategy is to allow the second zenMethod call but to do one of
two options:
A) Save the internal flag used by the Deferred Refresh mechanism to
prevent recursive refreshes.
This can be done by saving the zenRefreshMode variable and setting it to
2 prior to making the
synchronous call. This will turn off refreshes so the original value of
this flag should be restored
immediately after the synchronous call.
B) Invoke the nested ZenMethod call "later". This is done by using the
zenSetDeferredAction(func,0)
technique to execute func as soon as possible (as soon as we are finished).
/// Set a deferred action.
/// A deferred action is fired after a specified delay. If another
/// deferred action is set in the meantime, the first is never fired.
function zenSetDeferredAction(func,delay)
This is an excellent technique to serialize the ZenMethod calls an
avoids any synchronization
issues that could occur. Depending on how the function passed in the
formal argument "func" is defined,
it may require an advanced JavaScript called a closure to keep track of
private variables.

I am not aware of any other causes of this error, so I hope that this
response will be helpful to
you. If you need assistance please do log a WRC ticket and support can
assist you

Best Regards,
Derek Day


Dawn Wolthuis wrote (12/5/08 3:25 PM):

Dawn Wolthuis

unread,
Dec 5, 2008, 3:55:07 PM12/5/08
to InterSys...@googlegroups.com
Thanks for helping my persistence pay off on this one, Derek! With an
initial read, this looks very helpful. Now I just have to understand
it all and we will be golden, right?

Any chance you could give an example of some javascript code, perhaps
a method with a table refresh, that illustrates one or more of these
ways to get rid of these zen assertions?

These often occur when the user moves to a new tab. I have not studied
your response enough yet to fully understand or know if there is
something we could do when we move to a new tab (we have an onshowTab
method) to help avoid these. I will study this over the weekend, but
if you have a thought on that, let me know.

Thanks a bunch! --dawn

pfc

unread,
Dec 5, 2008, 3:57:32 PM12/5/08
to InterSys...@googlegroups.com
Dawn

How are you doing?

I am also staring to get worried about these
Working on an internal intranet with 15-20 users - they tell me that they
see the Zen Assertion errors often (don't ask me for how often).

I development I only see these infrequently when there is some cr*p code
being developed (never makes it to the release - honestly :})

So what's going on?
I *suspect* that it's a timing issue - it happened to me once recently
whilst I was demo'ing to an end user - I think I clicked to quickly on a
previous page and the click was carried forward to the next page which
responded to the click before the DOM was initialised.

= =
Bit concerned by the very next email from Derek...

He seems to be saying that it's down to us developers to debug this...

Fine. But...
I never see any such assert errors in code that I have debugged and am now
releasing
Even so end users see an asset error (rarely but too often to be
comfortable)
So how do I debug it??? -
Try again and it works fine.
Ask them to recall how many clicks they did (impossible)
Do trace messages - again impossible to re-create exactly the clicks and
timings

Re-reading again Derek's email - it's totally impossible for application
developers - this is all stuff for the ZEN developers...
Should I not call zen("someTable").executeQuery() (an async method) and NOT
expect it to work (and so on).

Perhaps we should not do async calls - fine - but we, as app developers have
no control over what the zen components are doing

= =

And, yes, I agree with you that this is a show stopper form an end user
experience view


Thoughts please


Peter
__________ Information from ESET NOD32 Antivirus, version of virus signature
database 3667 (20081205) __________

The message was checked by ESET NOD32 Antivirus.

http://www.eset.com



pfc

unread,
Dec 5, 2008, 4:03:40 PM12/5/08
to InterSys...@googlegroups.com
Hey Dawn

All our emails are crossing....

Just a quick thought
How are you implementing tabs?

I looked at the Zen tabs and discarded them for the following reasons
a) Don't trust myself - Too much code in a single class to control
b) Don't trust the browser to clear memory
c) Don't trust ISC to get all the initialisation/timing right


What I do to implement a tabbed motif is to have the tabs load (from afresh)
a new url - it looks tabbed but in fact they are separe page deliveries

= =
And as you are I too am going to study Derek's last

Peter

-----Original Message-----
From: InterSys...@googlegroups.com
[mailto:InterSys...@googlegroups.com] On Behalf Of Dawn Wolthuis

Dawn Wolthuis

unread,
Dec 5, 2008, 4:19:51 PM12/5/08
to InterSys...@googlegroups.com
You have no idea how happy I am to hear someone else beat this drum,
Peter. Thanks!! I, too, "feel" that this doesn't seem like an app
developer error. I would much rather get a javascript error message
than one of these if there is a bug in my js syntax, for example.

Derek does indicate that it isn't _always_ "our fault", but I am in
complete agreement that these crop up too often and are really
difficult to nail down and fix or work-around the problem. I thought
they were turning my hair gray, but upon return from the hair dresser
-- nope, not a gray hair in sight (perhaps a work-around there).

I'll confess that my application-developer's mind doesn't have enough
understanding of what Derek is saying to know what actions to take
just yet, but I am very encouraged that I got an answer, and I have
confidence that if the conversation continues (maybe drops down to my
level, or "up" depending on perspective), we will get somewhere on
this front. There was even a hint in Derek's response that there might
be bug fixes for this in future releases, I think, maybe, perhaps??

In any case, glad to hear your voice on this topic too, Peter. This is
one headache I would really like to get beyond. Cheers! --dawn

Dawn Wolthuis

unread,
Dec 5, 2008, 4:39:52 PM12/5/08
to InterSys...@googlegroups.com
On Fri, Dec 5, 2008 at 3:03 PM, pfc <p...@xisltd.net> wrote:
>
> Hey Dawn
>
> All our emails are crossing....
>
> Just a quick thought
> How are you implementing tabs?

I evaluated a bunch of options for the UI up front and decided to use
the tabGroup as delivered with Zen. I really prefer not to have the
user experience of going to another page as either they move or we
move them from tab to tab in a single application.

> I looked at the Zen tabs and discarded them for the following reasons
> a) Don't trust myself - Too much code in a single class to control

Yes, this was initially my biggest concern. I tried a few options,
such as making a separate component for each tab page (had problems
with dataControllers and the complexity of writing code for components
compared to pages, we were/are just too green) and putting a single
iframe on each tab (had UI or other issues with -- not recalling
clearly now).

We are working to do some more abstracting of functionality so that
there are more javascript functions or mv subroutines as visions of
pages of COBOL spewing out on greenbar have occasionally flooded over
me. We have a page template, with a subclass of that for another
template for some pages, and are looking at doing more with
subclassing pages, both for reuse and reduction of the page size.

> b) Don't trust the browser to clear memory

We have not experienced problems of which I am aware in that regard so
far. We might not be doing anything as complex, but we do have pages
with users going through 7 tabs, 3 of which have tables on them, and
have not noticed memory problems. Under what conditions would you be
anticipating what types of problems -- PC slow-down due to excessive
memory used or problem isolated to the browser?

> c) Don't trust ISC to get all the initialisation/timing right

Well, I don't trust M$ with IE, but I have much more confidence that
if there is a significant issue with ISC, that they will address it.
You are right to do some risk assessment in that regard, however.

> What I do to implement a tabbed motif is to have the tabs load (from afresh)
> a new url - it looks tabbed but in fact they are separe page deliveries

I think I recall you saying that, but other than the zen assertions
and page sizes (both run-time and source code), I have not yet had
reason to reconsider our strategy. I'm happy with the tabs, in
general.

> = =
> And as you are I too am going to study Derek's last

Good deal. Feel free to pass along what you learn, without assuming I
have a clue. cheers! --dawn

Derek Day

unread,
Dec 5, 2008, 7:17:20 PM12/5/08
to InterSys...@googlegroups.com
Yes we are working on it -- hopefully this entire class of errors will
"go away" and developers will have lot more flexibility -- so that a
bunch of stuff that does not now work nicely will "just work".

I really meant to say what Peter said -- c--- code will generate this
more than others. I can ellaborate more on the "timing" nature but
hopefully this can be fixed before that is necessary.
~Derek

Dawn Wolthuis wrote (12/5/08 4:19 PM):

Derek Day

unread,
Dec 5, 2008, 9:16:27 PM12/5/08
to InterSys...@googlegroups.com
Also thank Olivier C. He was seeing this in a complex project and was
very persistent in advocating for the developer -- I'm sure encouraged
by your emails, Dawn.

This is a case where I am detecting that we are in the middle of a
refresh so I avoid an immediate server call. This is a modification of
the rowSelected method in ZENMVC.MVCMasterDetail.cls in SAMPLES.

According to the mechanism currently used to prevent Zen programs from
encountering inconsistent sets of object synchronization information,
the sample code should *always* produce an assertion error. Users of
Microsoft Web Servers not using web gardens or application pooling will
not often see the assertion failure, while Unix users will see it much
more often unless they are using the CSP NSD architecture. The reason
for this is that the mechnism is using the server job number to identify
compatible updates. A much more sophisticated mechanism is being
developed that will guarantee the consistency of the object sets passed
to and from the server.

To understand the underlying issue, consider that multiple asynchronous
server calls can be pending. Requests #1 and #2 are send out contain
objects States (A1+B1) and (A2+C1) respectively, when the responses are
received, the order of the responses will cause a different state
(either A2+B1+C1) or (A1+B1+C1) on the browser which may cause
unpredictable behavior based on network load. -- I think that makes
sense! I had nice diagram drawn up on my whiteboard from my initial
analysis when I reported this to development and it was still there when
I put together the document below.

I tested the example below by modifying the deferred mode logic to give
me consistent assertion failures. I found that dealing with those
assertion failures that were easy to reproduce forced me to write more
efficient code -- so I think the concepts are helpful to understand for
other extremists out there even after the mechanism is improved.

The code below is triggered by any table refresh in addition to mouse
clicks and keyboard events. I considered using which=="" instead of
zenRefreshMode==1, the which argument is "" when a
programmatic/synthetic event causes the onRowChange event to be fired.

/// Row in Master table select; update controller.
/// <var>which</var> indicates how this event was fired.
Method rowSelected(table, which) [ Language = javascript ]
{
var controller = zenPage.getComponentById('source');
if (controller.getModelId()==table.getValue()) { return; }
if (('keypress' == which)||(zenRefreshMode==1)) {
// defer this action in case the user is arrowing through a
number of items
var id = table.getValue();
var action = new
Function("zenPage.getComponentById('source').setProperty('modelId','"+id+"');");

zenSetDeferredAction(action,200);
}
else {
// select immediately
var id = table.getValue();
controller.setProperty('modelId',id);
}
}

Dawn Wolthuis wrote (12/5/08 3:55 PM):

Derek Day

unread,
Dec 5, 2008, 9:19:36 PM12/5/08
to InterSys...@googlegroups.com
Peter can you try the NSD mode -- (I am betting that you are using the
multi-process Apache on Unix)? It should reduce the times you see this.
Increasing the minimum number of connections to 20 in the CSP Gateway
may also help so that each user is more likely to get their own
connection. (The problem happens when requests are serviced by different
server processes *and* when the application code has certain features).

Thanks,
Derek

pfc wrote (12/5/08 3:57 PM):

pfc

unread,
Dec 6, 2008, 12:44:01 AM12/6/08
to InterSys...@googlegroups.com
Derek

Thanks for the posts and info will study

As regards the errors it only came to light last week and I do not have a
handle on the frequency
Fortunately I have a captive audience of employees so can do this fairly
easily.

The platform is plain old Windoze 2003 server 16 with mostly IE7 (am working
on making it cross browser) bit so nothing special there.

Will collect some info and report back


Peter

-----Original Message-----
From: InterSys...@googlegroups.com
[mailto:InterSys...@googlegroups.com] On Behalf Of Derek Day
Sent: 06 December 2008 02:20
To: InterSys...@googlegroups.com
Subject: [InterSystems-Zen] Re: Debugging Zen Assertions


__________ Information from ESET NOD32 Antivirus, version of virus signature
database 3668 (20081206) __________

pfc

unread,
Dec 6, 2008, 2:10:30 AM12/6/08
to InterSys...@googlegroups.com
Derek

Intrigued by your sentence

" I found that dealing with those assertion failures that were easy to
reproduce forced me to write more efficient code"

Could you discuss this a bit please

Peter

Dawn Wolthuis

unread,
Dec 6, 2008, 9:39:43 AM12/6/08
to InterSys...@googlegroups.com
We are running multi-process apache on unix. We are running in NSD
mode. We will increase to 20 and see if that helps. [Since my IP
address has changed since the last time I went to the CSP Gateway
config, I have to find the right config file to place my IP address so
I can use it again.]

Our code is not in production, but I thought I would indicate what
happens here since it can give more hints regarding the
developer-experience with this issue. This is often a "Friday problem"
for me since on Fridays I often spin through smaller tickets and
"nits" doing more minor code changes, trying to get as many tickets
turned around as I can. Yesterday I had just gotten to the point of
starting this process, later than I had hoped, when I changed a label
in a page for which I was not the primary author. I made the
label="text" change to that text, something the 20-something me would
not have tested, then ran a unit test. It worked, so I checked it in
and tested it in a verification account (what could fail, right?) in
our process to getting it staged for the next build. My payback for
being meticulous in my testing of a teeny tiny change is that the code
actually did fail. In that verification account I got the Zen
assertions. Arghhh. I am sure you can see how that can put a dent in
a developer's day. Total tickets closed yesterday: 0 (not just for
this reason, of course). And, once again, don't forget that there is
no happy hour here among the Calvinists in NW Iowa. smiles --dawn

pfc

unread,
Dec 7, 2008, 12:00:32 PM12/7/08
to InterSys...@googlegroups.com
Dawn

Just to close off the discussion...

Part of my thought process for doing what I do is probably dated - I
evaluated the different options around 2 years ago

a. Trust myself....
This is still true - I am developing multi tabs each with very complex
logic/code to mix these into a single page would make it difficult to
maintain. Also would be concerned about the size resulting source code size
causing compilation problems (have seen others referring to this)

b. memory leaks....
I think things have probably improved in this area with new patches etc.

c. ISC Issues
In the original ZEN I believe there were problems, I remember an article
from Jon Pain on this ages ago - again things have improved.

So it really is (a) that is the main reason for continuing to do what I do

Also maybe another reason....

If it's all in a single page everything gets dl'd every time even if the
tabs are not used. Though this is a swings and roundabouts. What I do is
that every tab is called on clicking it so the first tab is quicker to dl
but there is a hit for each tab.

Peter


peter


Dawn Wolthuis

unread,
Dec 7, 2008, 1:51:37 PM12/7/08
to InterSys...@googlegroups.com
On Sun, Dec 7, 2008 at 11:00 AM, pfc <p...@xisltd.net> wrote:
>
> Dawn
>
> Just to close off the discussion...

What, you think you get the last word ;-) [just kidding, of course] --
a couple of comments below.

> Part of my thought process for doing what I do is probably dated - I
> evaluated the different options around 2 years ago
>
> a. Trust myself....
> This is still true - I am developing multi tabs each with very complex
> logic/code to mix these into a single page would make it difficult to
> maintain. Also would be concerned about the size resulting source code size
> causing compilation problems (have seen others referring to this)
>
> b. memory leaks....
> I think things have probably improved in this area with new patches etc.
>
> c. ISC Issues
> In the original ZEN I believe there were problems, I remember an article
> from Jon Pain on this ages ago - again things have improved.

Yes, I recall someone mentioning that some things had been improved
regarding the tabs when we started (with 2008.2).

> So it really is (a) that is the main reason for continuing to do what I do
>
> Also maybe another reason....
>
> If it's all in a single page everything gets dl'd every time even if the
> tabs are not used. Though this is a swings and roundabouts. What I do is
> that every tab is called on clicking it so the first tab is quicker to dl
> but there is a hit for each tab.

I suspect that the set of functionality that you have for a single
page is also what we have for a single page, but that within each
page, we have our tabs, rather than as the top level navigation. Our
top level navigation between pages is with graphical buttons and menu
options which might be at the level of your tabs, where our tabs are
within a page making for a smaller number of fields on various forms
within the page, for example.

I am concerned about the sizes of the pages, but more so regarding the
run-time size than the source code size right now. Initially I was
very uncomfortable with OOP classes the size of COBOL programs, and
maybe I should still be more concerned about that, but they have not
grown too large so far. I also think that we will be able to do more
partitioning of the page code than we have done to date by abstracting
more js functions, server-side routines, and perhaps queries although
I can't figure out how to debug the Query methods so I have stopped
adding new ones at least temporarily, as well as shifting some code to
the model.

I have a hunch that we both did a reasonably good analysis of our
differing requirements regarding tabs when we chose to implement them
differently, and we can always try your approach in the future if we
find a reason to switch. cheers! --dawn

> Peter
>
>
> peter
Reply all
Reply to author
Forward
0 new messages