I created solution for exactly this type of issue. I use the Timing object (new in PB 6!)
Solution is to keep DB connection alive by "pinging" DB at regular interval, but delay that ping if app is in the middle of another DB transaction.
Code sample #1: How to use my timing object
// App's instance variables
PRIVATE timer_DbKeepAlive inv_keepAlive
// App's Open event last line
// Keep SQLCA connection alive using default setup
inv_keepAlive = create timer_DbKeepAlive
inv_keepAlive.of_StartTimer(SQLCA)
// App's Close event
if IsValid(inv_keepAlive) then inv_keepAlive.Stop()
TIP: If you have more DB connections simply create more timer instances and start a timer for each connection.
Code sample #2: Class = timer_DbKeepAlive inherits from Timing
// *** *** *** *** INSTANCE VARIABLES
PRIVATE:
transaction itr_SQLCA // DB connection to keep alive
long il_checkInterval = 1800 // Default: 30 minutes
long il_dbRestoreCount
// Configurable "constants"
long MIN_CheckInterval = 60 // 1 minute
long MAX_RestoreCount = 10
// -----------------------------------------------------------------------
// *** *** *** *** PUBLIC FUNCTION of_StartTimer(transaction atr_sqlca)
// Start "Keep Alive" for
itr_SQLCA = atr_SQLCA
this.Start(il_checkInterval)
// -----------------------------------------------------------------------
// *** *** *** *** EVENT Timer( )
// Ping database (MSSQL syntax) to keep connection alive.
datetime ldt_now
SELECT GetDate() INTO :ldt_now FROM (SELECT 1 a) dummy USING itr_SQLCA;
if itr_SQLCA.SQLCode = 0 then
this.of_LogStillAlive(ldt_now)
else
// Connection dead despite keep alive signal
il_dbRestoreCount ++
if il_dbRestoreCount > MAX_RestoreCount then
this.of_LogAbortTooManyFailures()
HALT CLOSE // !!! ABORT !!!
end if
// Restore connection
DISCONNECT USING itr_SQLCA;
CONNECT USING itr_SQLCA;
// Reduce interval to avoid repeated failure
if il_checkInterval > MIN_CheckInterval then
il_checkInterval /= 2
else
il_checkInterval = MIN_CheckInterval
end if
this.Start(il_checkInterval)
end if
Code sample #3: Utility function on class = timer_DbKeepAlive
Functions to set the MIN/MAX values and default interval. And function to LOG (here no action)
// *** *** *** *** PUBLIC FUNCTION of_SetRestoreCount(long al_maxRestoreCount)
MAX_RestoreCount = al_maxRestoreCount
// Sanity check: MAX >= 0
if MAX_RestoreCount < 0 then
MAX_RestoreCount = 0
end if
// -----------------------------------------------------------------------
// *** *** *** *** PUBLIC FUNCTION of_SetCheckInterval(long al_initialInterval_seconds, long al_minimumInterval_seconds)
il_checkInterval = al_initialInterval_seconds
MIN_CheckInterval = al_minimumInterval_seconds
// Sanity check: MIN >= 15 seconds
if MIN_CheckInterval < 15 then
MIN_CheckInterval = 15
end if
// Sanity check: Current >= MIN
if il_checkInterval < MIN_CheckInterval then
il_checkInterval = MIN_CheckInterval
end if
// -----------------------------------------------------------------------
// *** *** *** *** PROTECTED FUNCTION of_LogStillAlive(datetime adt_AliveTimeStamp)
// LOG that DB connection is still alive at .
// . . .
// -----------------------------------------------------------------------
// *** *** *** *** PROTECTED FUNCTION of_LogAbortTooManyFailures( )
// LOG that app will abort due to too many DB reconnect attempts.
// . . .
Feel free to copy and adapt as needed. Ensure your global variables don't use same names as the instance variables.