Skip to content

Instantly share code, notes, and snippets.

@bubnenkoff
Created September 4, 2021 06:35
Show Gist options
  • Save bubnenkoff/65fa684a3de218bab6102453df3f79fe to your computer and use it in GitHub Desktop.
Save bubnenkoff/65fa684a3de218bab6102453df3f79fe to your computer and use it in GitHub Desktop.
import 'dart:async';
import 'package:parser_monitor_server/Services/Database.dart';
import 'package:parser_monitor_server/Services/Globals.dart';
import 'package:postgres/postgres.dart';
enum CacheLevel {
oneMinute,
tenMinutes,
oneHour,
oneDay
}
class RequestCacheStruct {
int requestHash;
DateTime requestDate;
PostgreSQLResult requestResult;
bool? markedAsOutDate;
RequestCacheStruct(this.requestHash, this.requestDate, this.requestResult);
}
class QueryResultCache {
List<RequestCacheStruct> requestsCacheList = [];
// Если один и тот же запрос отправлен два раза подряд, то второй точно такой же выполнять нет смысла
Map<int, Future<PostgreSQLResult>> pendingFutures = {};
Future<void> addResultToCache(sqlQuery) async {
try {
if(pendingFutures.containsKey(sqlQuery.hashCode)) {
print('This query is already running');
await pendingFutures[sqlQuery.hashCode];
// await pendingFutures.remove(sqlQuery.hashCode); // удаляем обработанную Future из списка
}
else {
pendingFutures.addAll({sqlQuery.hashCode: connection.query(sqlQuery, timeoutInSeconds: 3600)});
var queryResult = await pendingFutures[sqlQuery.hashCode]; // выполняем отложенную Future
var queryObj = RequestCacheStruct(sqlQuery.hashCode, DateTime.now(), queryResult! );
requestsCacheList.add(queryObj);
await pendingFutures.remove(sqlQuery.hashCode); // удаляем обработанную Future из списка
// pendingFutures.addAll({
// sqlQuery.hashCode: connection.query(sqlQuery, timeoutInSeconds: 3600)
// .then((queryResult) {
// var queryResult = pendingFutures[sqlQuery.hashCode]; // выполняем отложенную Future
// })
// }
// );
print('Query was added to сache');
}
}
on TimeoutException catch(e) {
print('!!!TimeoutException: ${e.message}' );
// rethrow делать пока не нужно -- мы не знаем как обрабатывать ошибку уровнем выше
// rethrow;
}
on PostgreSQLException catch(e) {
print('PostgreSQLException: ${e.message}' );
rethrow;
}
on Exception catch(e) {
print('Base Exception: ${e}' );
}
}
// результат есть где-то в кэше
PostgreSQLResult getResultFromCache(sqlQuery) {
return requestsCacheList.firstWhere((element) => element.requestHash == sqlQuery.hashCode).requestResult;
// for (var req in requestsCacheList) {
// if(req.requestHash == sqlQuery.hashCode) {
// return req.requestResult;
// }
// }
}
bool isQueryInCache(sqlQuery, cacheLevel) {
// requestsList.any((element) => element.requestHash == el.requestHash);
// if(requestsList.isEmpty) return false;
for(var req in requestsCacheList) {
if(req.requestHash == sqlQuery.hashCode) {
// теперь нужно проверить на сколько устарел запрос по сравнению с временем кэширования
if(cacheLevel == CacheLevel.oneMinute) {
if( req.requestDate.isBefore( DateTime.now().subtract(Duration(minutes: 1)) )) {
req.markedAsOutDate = true;
}
}
if(cacheLevel == CacheLevel.tenMinutes) {
if( req.requestDate.isBefore( DateTime.now().subtract(Duration(minutes: 10)) )) {
req.markedAsOutDate = true;
}
}
if(cacheLevel == CacheLevel.oneHour) {
if( req.requestDate.isBefore( DateTime.now().subtract(Duration(minutes: 60)) )) {
req.markedAsOutDate = true;
}
}
if(cacheLevel == CacheLevel.oneDay) {
if( req.requestDate.isBefore( DateTime.now().subtract(Duration(hours: 24)) )) {
req.markedAsOutDate = true;
}
}
}
}
requestsCacheList.removeWhere((element) => element.markedAsOutDate == true);
// print("requestsList: $requestsList");
var result = requestsCacheList.any((element) => element.requestHash == sqlQuery.hashCode);
if(result) {print('Request is in cache');}
else {print('Request is NOT in cache');}
return result;
}
Future<PostgreSQLResult?> executeQuery(sql, cacheLevel) async {
// если в кэше нет ничего то возвращается null
// можно без null но тогда нужно придумать как реализовать пустой PostgreSQLResult
PostgreSQLResult? result;
// if (queryResultCache.isQueryInCache(sql, cacheLevel)) {
// result = await queryResultCache.getResultFromCache(sql);
// }
// else {
// await queryResultCache.addResultToCache(sql);
// result = await queryResultCache.getResultFromCache(sql);
// print("here potential null: $result");
// }
if (!queryResultCache.isQueryInCache(sql, cacheLevel)) {
await queryResultCache.addResultToCache(sql);
}
result = await queryResultCache.getResultFromCache(sql);
print("here potential null. Don't know why: $result");
return result;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment