<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div><div><div>On Mar 16, 2013, at 2:05 AM, Philippe Marschall wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><div>On Thu, Mar 14, 2013 at 7:12 PM, Ken Treis &lt;<a href="mailto:ken@miriamtech.com">ken@miriamtech.com</a>&gt; wrote:<br><blockquote type="cite">We have build something using the Seaside-Rest add-on, and everything works beautifully in GemStone until a transaction conflict triggers a retry -- at which point we get a 404 rather than the expected response.<br></blockquote><br>Can you provide a bit more detail about the retry code? Where (server<br>adapter,filter, ...) does it run and what does it look like?<br></div></blockquote><div><br></div>It's in a server adaptor that was stitched together from Dale's standard code for GemStone, a streaming hack for Zinc, and a quick back-port of your WAComboResponse for use in Seaside 3.0. Code is available at <a href="http://mc.miriamtech.com/zinc">http://mc.miriamtech.com/zinc</a></div><div><br></div><div>The starting point is WAGsZincStreamingAdaptor&gt;&gt;handleRequest: aRequestContext</div><div><br></div><div>1. Spins until we get necessary GS locks.</div><div>2. Attempts to process the request</div><div>3. Tries to commit the GS transaction.</div><div>4. If commit fails, abort and attempt to process again.</div><div><br></div><div>Details below. This is really a GemStone-specific issue, but my life would be simpler with something like #reset or #resetIfPossible on WAPathConsumer and/or WARequestContext.</div><div><br></div><div><div><div><blockquote type="cite"><div>Thinking about it you may actually need a bit more than just resetting<br>the path consumer. The properties on the request context and the<br>response buffer as well.<br></div></blockquote><div><br></div>I'm resetting the response buffer by sending #resetIfPossible, and we've hacked the path consumer reset into there, but I'm not doing anything with properties on the request context. What might need to be changed there?</div><div><br></div><div><div><div>Here's a quick overview of the retry-related code in&nbsp;WAGsZincStreamingAdaptor, with some GemStone-specific details left out or pseudo-coded for brevity.</div></div></div></div></div><div><br></div><div><b>handleRequest: aRequestContext</b></div><div><div><span class="Apple-tab-span" style="white-space:pre">        </span>| timeout |</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>timeout := Time now addSeconds: 60.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>[self handleRequestCheckingLock: aRequestContext]</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>whileFalse: [</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>Time now &gt; timeout</div><div><span class="Apple-tab-span" style="white-space:pre">                                </span>ifTrue: [</div><div><span class="Apple-tab-span" style="white-space:pre">                                        </span>|response|</div><div><span class="Apple-tab-span" style="white-space:pre">                                        </span>response := aRequestContext response.</div><div><span class="Apple-tab-span" style="white-space:pre">                                        </span>response internalError.</div><div><span class="Apple-tab-span" style="white-space:pre">                                        </span>response stream nextPutAll: 'The system is too busy, please try again in a moment.'.</div><div><span class="Apple-tab-span" style="white-space:pre">                                        </span>^self</div><div><span class="Apple-tab-span" style="white-space:pre">                                        </span>].</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>(Delay forMilliseconds: 10) wait.</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>aRequestContext consumer initializeWith: aRequestContext request url path copy ]</div></div><span></span><div><br></div><div>(I know, the path consumer reset feels out of place here... this was just a quick hack to make things work.)</div><div><br></div><div><div><b>handleRequestCheckingLock: aRequestContext</b></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>"answer false to retry request"</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>| result retryRequest |</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>GRPlatform current transactionMutex critical: [</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>retryRequest := false.</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>[ super handleRequest: aRequestContext ]</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>on: WARetryHttpRequest</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>do: [:ex |<span class="Apple-tab-span" style="white-space:pre">        </span>retryRequest := aRequestContext response isCommitted not&nbsp;].</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>retryRequest&nbsp;</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>ifTrue: [</div><div><span class="Apple-tab-span" style="white-space:pre">                                </span>"lock not acquired - unwind the stack to this point and leave transaction mode"</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre">                                </span>GRPlatform current doAbortTransaction.</div><div><span class="Apple-tab-span" style="white-space:pre">                                </span>^false ].</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>GRPlatform current doCommitTransaction</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>ifFalse: [&nbsp;</div><div><span class="Apple-tab-span" style="white-space:pre">                                </span>GRPlatform current doAbortTransaction.</div><div><span class="Apple-tab-span" style="white-space:pre">                                </span>aRequestContext response resetIfPossible</div><div><span class="Apple-tab-span" style="white-space:pre">                                        </span>ifTrue: [</div><div><span class="Apple-tab-span" style="white-space:pre">                                                </span>GRPlatform current&nbsp;saveLogEntry: 'Commit failure - retrying'.</div><div><span class="Apple-tab-span" style="white-space:pre">                                                </span>^false]</div><div><span class="Apple-tab-span" style="white-space:pre">                                        </span>ifFalse: [</div><div><span class="Apple-tab-span" style="white-space:pre">                                                </span>GRPlatform current saveLogEntry:&nbsp;'Commit failure after response sent, giving up'.</div><div><span class="Apple-tab-span" style="white-space:pre">                                                </span>^true]].</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>].</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>^true</div><div><br></div><div>My apologies for the poor code factoring/formatting.</div><div><br></div><div><div>Julian suggested creating a new context, which is something I hadn't considered but probably should...</div><div><br></div></div><div><br></div><div>Ken</div></div></div></body></html>