Skip to content

Commit 1563b13

Browse files
authored
Use redis cache for additional deduplication check. (dart-lang#8704)
1 parent 32ade8b commit 1563b13

File tree

2 files changed

+30
-10
lines changed

2 files changed

+30
-10
lines changed

app/lib/account/consent_backend.dart

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'package:_pub_shared/data/account_api.dart' as api;
66
import 'package:clock/clock.dart';
77
import 'package:gcloud/service_scope.dart' as ss;
88
import 'package:logging/logging.dart';
9+
import 'package:pub_dev/shared/redis_cache.dart';
910
import 'package:retry/retry.dart';
1011

1112
import '../account/agent.dart';
@@ -118,19 +119,31 @@ class ConsentBackend {
118119
kind: kind,
119120
args: args,
120121
);
121-
final query = _db.query<Consent>()..filter('dedupId =', dedupId);
122-
final list = await query.run().toList();
123-
if (list.isNotEmpty) {
124-
final old = list.first;
125-
if (old.isExpired()) {
122+
Consent? existing;
123+
124+
final dedupCacheEntry = cache.consentDedupLookup(dedupId);
125+
final cachedConsentId = await dedupCacheEntry.get();
126+
if (cachedConsentId != null) {
127+
final key = _db.emptyKey.append(Consent, id: cachedConsentId);
128+
existing = await _db.lookupOrNull<Consent>(key);
129+
}
130+
if (existing == null) {
131+
final query = _db.query<Consent>()
132+
..filter('dedupId =', dedupId)
133+
..limit(1);
134+
final list = await query.run().toList();
135+
existing = list.singleOrNull;
136+
}
137+
if (existing != null) {
138+
if (existing.isExpired()) {
126139
// expired entries should be deleted
127-
await _delete(old, (a) => a.onExpire(old));
128-
} else if (old.shouldNotify()) {
140+
await _delete(existing, (a) => a.onExpire(existing!));
141+
} else if (existing.shouldNotify()) {
129142
// non-expired entries just re-send the notification
130-
return await _sendNotification(activeAgent.displayId, old);
143+
return await _sendNotification(activeAgent.displayId, existing);
131144
} else {
132145
return api.InviteStatus(
133-
emailSent: false, nextNotification: old.nextNotification);
146+
emailSent: false, nextNotification: existing.nextNotification);
134147
}
135148
}
136149
// Create a new entry.
@@ -144,6 +157,7 @@ class ConsentBackend {
144157
consent,
145158
auditLogRecord,
146159
]);
160+
await dedupCacheEntry.set(consent.consentId);
147161
return await _sendNotification(activeAgent.displayId, consent);
148162
});
149163
}

app/lib/shared/redis_cache.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import '../../../service/rate_limit/models.dart';
2121
import '../../../service/security_advisories/models.dart';
2222
import '../../dartdoc/models.dart';
2323
import '../../shared/env_config.dart';
24-
import '../account/models.dart' show LikeData, SessionData;
24+
import '../account/models.dart' show Consent, LikeData, SessionData;
2525
import '../package/models.dart' show PackageView;
2626
import '../publisher/models.dart' show PublisherPage;
2727
import '../scorecard/models.dart' show ScoreCardData;
@@ -58,6 +58,12 @@ class CachePatterns {
5858
decode: (d) => SessionData.fromJson(d as Map<String, dynamic>),
5959
))[sessionId];
6060

61+
/// Cache for [Consent] mapping the `dedupId` to the `consentId`.
62+
Entry<String> consentDedupLookup(String dedupId) => _cache
63+
.withPrefix('consent-dedup-lookup/')
64+
.withTTL(Duration(minutes: 5))
65+
.withCodec(utf8)[dedupId];
66+
6167
Entry<String> uiPackagePage(String package, String? version) => _cache
6268
.withPrefix('ui-packagepage/')
6369
.withTTL(Duration(minutes: 10))

0 commit comments

Comments
 (0)