The following pseudocode examples illustrate how you can implement the described patterns.
Pattern 1 - Bulk Reporting
// The following procedure illustrates
Pattern 1 and should be
// executed only by a single background thread. During a given
// interval, it is designed to iterate calling the content publisher
// until NoResultsAvailableFault is detected or moreFlag is false.
//
proc Example_Pattern_1() {
while (true) {
boolean moreFlag = true
DataResponse response = null
while (moreFlag) {
try {
response = OC_GetTrackingData(“”, “”)
Example_ProcessData(response.data)
OC_AcknowledgeTrackingData(response.handle)
moreFlag = response.moreFlag
} catch (NoResultsAvailableFault) {
// All up-to-date
break
} catch (GeneralFault) {
// Error calling Get or Ack. No action required by caller.
break
} catch (AnyNonOCError) {
// Process the error…
// If the error occurred in Example_ProcessData
// then it is recommended that a call to
// OC_InitializeTrackingData()
// be made. This will ensure that any unacknowledged
// and potentially unprocessed TDRs will be resent
// on the next Get call.
break
}
}
sleep(RecommendedInterval)
}
}
Pattern 2 - End User Status
// The following procedure should be called as-needed for
// a specific user. It can be called simultaneously from many
// different threads. Do not use this pattern to satisfy
// the Use-case-01: Bulk Reporting.
//
proc Example_Pattern_2(username){
boolean moreFlag = true
DataResponse response
while (moreFlag) {
try {
response = OC_GetTrackingData(“”, username)
Example_ProcessData(response.data)
OC_AcknowledgeTrackingData(response.handle)
moreFlag = response.moreFlag
} catch (NoResultsAvailableFault) {
// All up-to-date
break
} catch (GeneralFault) {
// Error calling Get or Ack. No action required by caller.
break
} catch (AnyNonOCError) {
// Process the error…
// Due to the multi-threaded nature of this
// scenario, it is NOT recommended that a call to
// OC_InitializeTrackingData()
// be made here. This call should only be
// done by the Pattern 1 thread or the system
// startup thread.
break
}
}
}
// This code demonstrates how to implement a common
// processing module with a recommended recovery
// approach for
Pattern 2.
//
// How the setOfAlreadyProcessedIds functionality
// is implemented is internal and specific to each caller.
//
proc Example_ProcessData(TrackingDataRecord[] data) {
foreach record in data {
if (record.reset == 0) {
// Safe to process, the caller has not seen this before.
//
// Also check timestamp to perform any reconciliation
// if this record is older then any record already
// processed for the same user. Out-of-order records
// should not be an issue for different users.
write record to DB, this is
atomically adding record.id to setOfAlreadyProcessedIds
} else {
// May have seen this TDR before, check it. The
// following TDR attributes are available for
// reconciliation:
// - id
// - timestamp
if (record.id in setOfAlreadyProcessedIds) {
// skip this record we have already processed it before
} else {
// safe to process, the caller
// may have seen it but was not
// able to process and acknowledge it.
write record to DB, this is
atomically adding record.id to setOfAlreadyProcessedIds
}
}
}
}