samedi 6 juin 2020

Discart delay event to keep a real time cache

I have some tables of temporal data, for example:

- DeviceHealthEvent: DeviceId, Signal, Hourmeter, EventDate, LastChangedDate    
- DeviceStateEvent: DeviceId, StateID, TimeCategory, TimeSubCategory, EventDate, LastChangedDate    
- DevicePositionEvent: DeviceId, East, North, Altitude, Speed, Direction, EventDate, LastChangedDate
- DeviceUserEvent: DeviceId, UserID, ShiftID, EventDate, LastChangedDate

So, as we can see, a device has a lot of information being stored in different tables and these tables grow a lot and are constantly changing.

To avoid having to go to each table and search for the current device record, I thought of creating a table with all the latest information from Device:

- DeviceRealTime: DeviceId, Signal, Hourmeter, StateID, TimeCategory, TimeSubCategory, East, North, Altitude, Speed, Direction, UserID, ShiftID, LastChangedDate

This table will have a cache and each item of this cache refer to a device, I thought about updating this cache by subscribing to an event called AfterCommited of each temporal table.

To persist the cache of DeviceRealTime items in the database table I created a reminder that goes through the cache and updates the table.

Implementation:

public class DeviceRealtimeRepo: IDeviceRealtimeRepo<DeviceRealTime>
{
    private ConcurrentDictionary<int, DeviceRealTime> _cache;

    public DeviceRealtimeRepo()
    {
        DeviceHealthEventRepo.AfterCommited + = OnDeviceHealthEventAfterCommited();
        DevicePositionEventRepo.AfterCommited + = OnDevicePositionEventAfterCommited();
        DeviceUserEventRepo.AfterCommited + = OnDeviceUserEventAfterCommited();

        CreateReminder();
    }

    public DeviceRealTime GetItem(int id)
    {
        return GetOrCreate(id);
    }

    // Creates a Timer (and a BackgroundWorker) to call the OnExecuteReminder method every 30 seconds
    private CreateReminder()
    {
    }

    // callback that will update the DeviceRealTime table based on the _cache 
    private OnExecuteReminder()
    {
    }

    // update the cache item after a commit in the DeviceHealthEvent is done
    private void OnDeviceHealthEventAfterCommited(Action action, DeviceHealthEvent newtem, DeviceHealthEvent oldItem)
    {
    // how to discard a delayed item to keep the cache in the correct state???

        if (action == Actions.Add || action == Actions.Update)
        {
            DeviceRealTime cachedItem = GetOrCreate(newtem.DeviceId);
            cachedItem.Signal = newtem.Signal;
            cachedItem.Hourmeter = newtem.Hourmeter;
            cachedItem.LastChangedDate = DateTime.UtcNow();
        }
        else if (action == Actions.Delete)
        {
            TryRemove(newtem.DeviceId);
        }
    }

    private DeviceRealTime GetOrCreate(int deviceId)
    {
        DeviceRealTime cachedItem;
        if (!_cache.TryGetValue(deviceId, out cachedItem))
        {
            cachedItem = createItem();

            // Save data in cache
            _cache[deviceId] = cachedItem;
        }

        return cachedItem;
    }
}

Well, in summary, I haven't figured out a way to discard delay events of AfterCommited. For example, OnDeviceHealthEventAfterCommited is executed but the newItem is already overdue.

I don't know if there is an architectural desing that addresses this requirement.

Aucun commentaire:

Enregistrer un commentaire