It's all done in the web app...
Bruce gets the credit on the xfiles stuff as I needed his expertise to get it working. I log all my messages to disk which then helps me identify which tables were locked etc. Hope this helps. One app that restarted 5-6 times a day now runs for months on end. Another app my uses used to email me with SWOD (spinning wheel of Death) happened so often the app was almost unusable and caused them (and me) a lot of grief. Both fixed with the timeout stuff. I also run an app that comes with self service connectionchecker that also checks the app is running and if not restarts it.
I had this in it's own source procedure hooked off the indexpage so it regularly checked for locks.
CheckForLocks ROUTINE
p_web.SetSQLTimeout(ADJUST,net:on)
DUMMY{Prop:SQL} = 'Select Count(*) as Dum_Field01 From APPROVAL'
p_web.SetSQLTimeout(ADJUST,net:off)
Next(DUMMY)
If Errorcode()
Case Errorcode()
Of 33
p_web._trace('Lock on APPROVAL - restart errorcode=' & errorcode() & 'error=' & error() & ' ' & clip(glo:dbowner))
Message('Lock on APPROVAL - restart errorcode=' & errorcode() & 'error=' & error() & ' Threads=' & 'wp:NumberOfThreads')
p_web.RequestData.Webserver._wait()
xml1.save(p_web.RequestData.Webserver._SessionQueue,'sessionqueue.xml','table','record')
xml1.save(p_web.RequestData.Webserver._SessionDataQueue,'sessiondataqueue.xml','table','record')
p_web.RequestData.Webserver._release()
Chain(Command(0))
Of 90
p_web._trace('APPROVAL Busy=' & errorcode() & 'error=' & error() & ' ' & clip(glo:dbowner))
Message('APPROVAL Busy=' & errorcode() & 'error=' & error() & ' ' & glo:dbowner)
p_web.RequestData.Webserver._wait()
xml1.save(p_web.RequestData.Webserver._SessionQueue,'sessionqueue.xml','table','record')
xml1.save(p_web.RequestData.Webserver._SessionDataQueue,'sessiondataqueue.xml','table','record')
p_web.RequestData.Webserver._release()
Chain(Command(0))
Else
p_web._trace('APPROVAL Error=' & errorcode() & 'error=' & error() & ' ' & clip(glo:dbowner))
Message('APPROVAL Error=' & errorcode() & 'error=' & error() & ' Threads=' & 'wp:NumberOfThreads')
End
Else
End
***********************************
This stuff goes in the webserver procedure
GlobalErrors.SetProcedureName('WebServer')
! [Priority 800]
Message('Web Server started: ' & LongPath())
xml.TagCase = XF:CaseAny
xml.load(ThisWebServer._SessionQueue,'sessionqueue.xml','table','record')
xml.load(ThisWebServer._SessionDataQueue,'sessiondataqueue.xml','table','record')
***
ThisWindow.Kill PROCEDURE
ReturnValue BYTE,AUTO
! Start of "WindowManager Method Data Section"
! [Priority 5000]
! End of "WindowManager Method Data Section"
CODE
! Start of "WindowManager Method Executable Code Section"
! [Priority 50]
! ThisWebServer._Wait()
xml.save(ThisWebServer._SessionQueue,'sessionqueue.xml','table','record')
xml.save(ThisWebServer._SessionDataQueue,'sessiondataqueue.xml','table','record')
! ThisWebServer._Release()
****
xml.SaveCurrentFieldToXML PROCEDURE (Long p_x,Long p_DimCounter,String p_name)
! Start of "Class Method - Data Section"
! [Priority 5000]
a string(1)
! End of "Class Method - Data Section"
CODE
! Start of "Class Method - Executable Code Section"
! [Priority 50]
! xfiles doesn't do &Strings well (yet), so we need to give it a hand here, when saving.
if lower(p_name) = 'extvalue'
if thisWebServer._SessionDataQueue.ExtValue &= Null
self.currentfield &= a
else
self.currentfield &= thisWebServer._SessionDataQueue.ExtValue
end
end
******
xml.AssignField PROCEDURE (String pString)
! Start of "Class Method - Data Section"
! [Priority 5000]
! End of "Class Method - Data Section"
CODE
! Start of "Class Method - Executable Code Section"
! [Priority 50]
! the incoming queue contains the length of memory set aside for the (bigger) session values.
! and big values are stored in extvalue, not value. Extvalue is a pointer ( &string) so we need to
! give xFiles some assistance here.
! This code will only work if extvaluesize is encountered _before_ extvalue.
case lower(self.CurrentTag)
of 'extvaluesize'
thisWebServer._SessionDataQueue.ExtValueLen = pString ! pString is a parameter to this method, not the pString data type.
thisWebServer._SessionDataQueue.ExtValue &= new(string(thisWebServer._SessionDataQueue.ExtValueLen))
return
of 'extvalue'
if pString <> ''
thisWebServer._SessionDataQueue.ExtValue = pString
end
return
end
*****