Я сейчас пишу аналитическую систему. В настоящее время он кэширует события в оперативной памяти. Он записывает в файловую систему через NSUserDefaults (iOS) и SharedPreferences (Android), когда приложение закрывается, как JSON. Эти данные читаются при открытии приложения.
Он также отправляет каждые N секунд или когда количество событий достигает 20. Когда отправка прошла успешно, он удаляет все события, отправленные из ОЗУ.
Это имеет очевидный fl aws: при сбое приложения все данные за N секунд теряются. Когда не удается связаться с сервером (например, из-за того, что сервер не работает) и происходит сбой приложения, еще больше данных теряется.
Мой вопрос здесь такой: как я могу повысить «безопасность» своих данных и предотвратить массовое потеря данных, когда сервер недоступен или недоступен?
Вот мой текущий код (удалены неважные части)
import Foundation
class BackendTrackingHandler : TrackingHandler {
static let KEY_CACHE_EVENT = "TrackingCache"
private static let SEND_INTERVAL:TimeInterval = 10
var cachedEvents: [TrackingEvent] = []
var temporaryCachedEvents: [TrackingEvent] = []
var prefix: String
var endpoint: String
var timer : Timer?
//whether we currently wait for a response
var isSending: Bool = false
override init() {
//init
readCachedEventsFromDisk()
timer = Timer.scheduledTimer(timeInterval: BackendTrackingHandler.SEND_INTERVAL, target: self, selector: #selector(send), userInfo: nil, repeats: true)
}
override func trackEvent(_ event: TrackingEvent) {
cachedEvents.append(event)
if((cachedEvents.count) >= 20) {
send()
}
}
@objc func send() {
if((cachedEvents.count) < 1) {
return
}
if(isSending) {
return
}
isSending = true
let enc = JSONEncoder()
enc.outputFormatting = .prettyPrinted
let data = try! enc.encode(cachedEvents)
// Constructring Request here
let session = URLSession.shared
//while the request is on the way, we can trigger new events. Make a temporary copy
temporaryCachedEvents = cachedEvents
let taksID = UIApplication.shared.beginBackgroundTask()
let task = session.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) -> Void in
if(error != nil)
{
self.isSending = false
UIApplication.shared.endBackgroundTask(taksID)
}else {
let httpResponse = response as! HTTPURLResponse
if(httpResponse.statusCode >= 200 && httpResponse.statusCode <= 299) {
//success, Data was sent so we can create a new cached event
//remove all events we already sent
self.cachedEvents = self.cachedEvents.filter{!self.temporaryCachedEvents.contains($0)}
self.isSending = false
UIApplication.shared.endBackgroundTask(taksID)
}else {
self.isSending = false
UIApplication.shared.endBackgroundTask(taksID)
}
}
}
task.resume()
}
func readCachedEventsFromDisk() {
let dec = JSONDecoder()
guard let data = UserDefaults.standard.data(forKey: BackendTrackingHandler.KEY_CACHE_EVENT) else {
cachedEvents = []
return
}
do {
cachedEvents = try dec.decode([TrackingEvent].self, from: data)
} catch {
cachedEvents = []
}
}
func writeCachedEventsToDisk() {
let enc = JSONEncoder()
let data = try! enc.encode(cachedEvents)
UserDefaults.standard.set(data, forKey: BackendTrackingHandler.KEY_CACHE_EVENT)
}
override func onApplicationBecomeActive() {
}
override func onApplicationBecomeInactive() {
let taskID = UIApplication.shared.beginBackgroundTask()
writeCachedEventsToDisk()
UIApplication.shared.endBackgroundTask(taskID)
}
}
€ dit: TrackingEvent
- это структура, которая используется несколькими TrackingHandler
s. Существует еще FirebaseTrackingHandler
, который предназначен для параллельной работы нашей собственной аналитической системы.