[
https://issues.apache.org/jira/browse/WICKET-6861?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17270053#comment-17270053
]
Sven Meier commented on WICKET-6861:
------------------------------------
Yes, you're right🤦♂️
I don't think we can solve this problem in Wicket, without building a huge
housekeeping of pending and running timers.
Here's another idea:
Attach the timeBehavior to a component that will be invisible after form
submit, then Wicket will not send that Ajax request.
> Possible race condition in clearing and triggering of Wicket timers
> -------------------------------------------------------------------
>
> Key: WICKET-6861
> URL: https://issues.apache.org/jira/browse/WICKET-6861
> Project: Wicket
> Issue Type: Bug
> Components: wicket-core
> Affects Versions: 9.2.0
> Reporter: Emond Papegaaij
> Priority: Minor
>
> In our test suite we see some intermittent failures related to
> {{AbstractAjaxTimerBehavior}}. At a few places in our application, we use a
> background poller at a 1 sec interval that checks for an out-of-band
> submission of the form data. So the user either has to fill the form via the
> web interface or via some other route. Either route can complete the form,
> but as soon as one of the two is triggered, the other must stop. The race
> condition lies in the {{AbstractAjaxTimerBehavior}} triggering while the user
> has already submitted the form manually.
> The naive implementation would stop {{AbstractAjaxTimerBehavior}} via
> {{Wicket.Timer.clear('timer0')}} in the Ajax response of the form submit.
> However, this results in a very large gap between the moment of submission
> and the actual moment the timer is stopped. To fix this, we've added the
> following code to the {{AjaxSubmitLink}}:
> {code:java}
> @Override
> public void renderHead(IHeaderResponse response) {
> super.renderHead(response);
> response.render(OnDomReadyHeaderItem.forScript(
> "Wicket.Event.add('" + getMarkupId() + "', 'click', " +
> "function() {Wicket.Timer.clear('" + getTimerId() + "');})"));
> }
> {code}
> This puts the call to {{Wicket.Timer.clear}} before the actual Ajax submit
> and should therefore prevent the timer from triggering after the Ajax submit
> is done. However, in very rare occurrences we still see the timer triggering.
> When it happens, the timer is always directly after the Ajax submit (often
> within 10ms). This makes us believe the current implementation has a race
> condition in the following way:
> * The user clicks the Ajax submit link
> * The execution of the event handlers is started in the browser
> * At this moment the {{setTimeout}} triggers, but it is suspended because JS
> is single threaded and the browser is already execution JS in response to UI
> interaction
> * The first event handler now clears the timer
> * The second event handler performs the Ajax call
> * Now the JS executor is freed and the timer function is executed
> Although I'm not entirely at home in the execution model of JS in a browser,
> this is the only explanation I could come up with. There is no way to
> reproduce it, other than run a complex test suite 1000ths of times. My
> proposed fix is to replace the timeout function in {{wicket-ajax-jquery.js}}
> in {{Wicket.Timer.set}} with this:
> {code:javascript}
> Wicket.TimerHandles[timerId] = setTimeout(function() {
> if (timerId in Wicket.TimerHandles) {
> Wicket.Timer.clear(timerId);
> f();
> }
> }, delay);
> {code}
> This should prevent the function {{f()}} to be executed after the timer has
> been cleared (Wicket.Timer.clear deletes the {{timerId}} from
> {{Wicket.TimerHandles}}.
--
This message was sent by Atlassian Jira
(v8.3.4#803005)