If you are using threads (forking Smalltalk processes) in your Seaside application, then you will need to make some relatively minor mods to your code.
In addition to managing concurrent access to objects (via critical blocks), all threads must be coordinated in relation to transaction boundaries. You cannot afford to have multiple threads aborting and committing without some sort of coordination – the method SeasidePlatformSupport class>>doTransaction: provides that coordination.
SeasidePlatformSupport class>>doTransaction: acquires the transactionMutex, performs a beginTransaction, evalutes the block passed in as an argument, performs a commitTransaction and returns the result of the commitTransaction (a Boolean). The transactionMutex ensures that your transaction will not interfere with any other ongoing transaction, including servicing an HTTP request.
In the SqueakSource Seaside application, there is a CacheThread that runs once a day and the code looks like this:
startCacheThread self isCacheThreadRunning ifTrue: [ self stopCacheTread ]. cacheThread := [ self updateCache. self updateStatistics. (Delay forDuration: 1 day) wait. ] forkAt: Processor userBackgroundPriority
After adding a call to SeasidePlatformSupport class>>doTransaction:, the code looks like this:
startCacheThread self isCacheThreadRunning ifTrue: [ self stopCacheTread ]. cacheThread := [ SeasidePlatformSupport doTransaction: [ self updateCache. self updateStatistics. ]. (Delay forDuration: 1 day) wait. ] forkAt: Processor userBackgroundPriority
If you choose to run the thread in the same VM as the Seaside application, you need to pay attention to how much time you spend inside of a doTransaction: block, because HTTP requests won’t be serviced while the block is executing.
If you’ve got long running transactions, then you should unconditionally move the thread into a separate GemStone VM. In the separate VM, the transaction duration will not affect the response times for HTTP requests.
Here’s an sample topaz script for running this thread in a separate VM (I’ll cover topaz in more detail in another post):
! ! Sample script for updating ! SSRepository cache and statistics ! set user DataCurator pass swordfish login run ! ! enter manual transaction mode and ! install SigAbort handler ! System transactionMode: #manualBegin. Exception installStaticException: [:ex :cat :num :args | System abortTransaction. System enableSignaledAbortError ] category: GemStoneError number: 6009 subtype: nil. System enableSignaledAbortError. ! ! Start update loop ! [true] whileTrue:[ SeasidePlatformSupport doTransaction: [ SSRepository updateCache. SSRepository updateStatistics. ]. (Delay forDuration: 1 day) wait. ]. %
If you have more than one thread in your Seaside application, you can fork off additional processes in the script.
My recomendation is that you plan on moving all of your background threads to a separate VM. In the long run it will be simpler to manage your threads and you won’t have to worry nearly as much about how long it takes individual operations to complete.