Skip to content

Commit fd4846e

Browse files
authored
Cached list of owned packages (#9131)
1 parent 3ac305e commit fd4846e

File tree

4 files changed

+52
-7
lines changed

4 files changed

+52
-7
lines changed

app/lib/account/backend.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,7 @@ Future<void> purgeAccountCache({required String userId}) async {
662662
await Future.wait([
663663
cache.userPackageLikes(userId).purgeAndRepeat(),
664664
cache.publisherPage(userId).purgeAndRepeat(),
665+
cache.userUploaderOfPackages(userId).purgeAndRepeat(),
665666
]);
666667
}
667668

app/lib/package/backend.dart

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,11 @@ class PackageBackend {
250250
}
251251

252252
/// Streams package names where the [userId] is an uploader.
253-
Stream<String> streamPackagesWhereUserIsUploader(String userId) async* {
254-
var page = await listPackagesForUser(userId);
253+
Stream<String> streamPackagesWhereUserIsUploader(
254+
String userId, {
255+
int pageSize = 100,
256+
}) async* {
257+
var page = await listPackagesForUser(userId, limit: pageSize);
255258
while (page.packages.isNotEmpty) {
256259
yield* Stream.fromIterable(page.packages);
257260
if (page.nextPackage == null) {
@@ -262,6 +265,17 @@ class PackageBackend {
262265
}
263266
}
264267

268+
/// Returns the cached list of package names, where the [userId] is an uploader
269+
/// (package is not under a publisher).
270+
Future<List<String>> cachedPackagesWhereUserIsUploader(String userId) async {
271+
final list = await cache.userUploaderOfPackages(userId).get(() async {
272+
return await streamPackagesWhereUserIsUploader(
273+
userId,
274+
).take(1000).toList();
275+
});
276+
return list as List<String>;
277+
}
278+
265279
/// Returns the latest releases info of a package.
266280
Future<LatestReleases> latestReleases(Package package) async {
267281
// TODO: implement runtimeVersion-specific release calculation
@@ -1522,6 +1536,11 @@ class PackageBackend {
15221536
asyncQueue.addAsyncFn(
15231537
() => _postUploadTasks(package, newVersion, outgoingEmail),
15241538
);
1539+
if (isNew && agent is AuthenticatedUser) {
1540+
asyncQueue.addAsyncFn(
1541+
() => cache.userUploaderOfPackages(agent.userId).purge(),
1542+
);
1543+
}
15251544

15261545
_logger.info('Post-upload tasks completed in ${sw.elapsed}.');
15271546
return (pv, uploadMessages);
@@ -1865,7 +1884,7 @@ class PackageBackend {
18651884
User uploader, {
18661885
required String consentRequestFromAgent,
18671886
}) async {
1868-
await withRetryTransaction(db, (tx) async {
1887+
final uploaderUserId = await withRetryTransaction(db, (tx) async {
18691888
final packageKey = db.emptyKey.append(Package, id: packageName);
18701889
final package = (await tx.lookup([packageKey])).first as Package;
18711890

@@ -1878,7 +1897,7 @@ class PackageBackend {
18781897
}
18791898
if (package.containsUploader(uploader.userId)) {
18801899
// The requested uploaderEmail is already part of the uploaders.
1881-
return;
1900+
return uploader.userId;
18821901
}
18831902

18841903
// Add [uploaderEmail] to uploaders and commit.
@@ -1892,7 +1911,9 @@ class PackageBackend {
18921911
package: packageName,
18931912
),
18941913
);
1914+
return uploader.userId;
18951915
});
1916+
await purgeAccountCache(userId: uploaderUserId);
18961917
triggerPackagePostUpdates(
18971918
packageName,
18981919
skipReanalysis: true,
@@ -1923,7 +1944,7 @@ class PackageBackend {
19231944
uploaderEmail = uploaderEmail.toLowerCase();
19241945
final authenticatedUser = await requireAuthenticatedWebUser();
19251946
final user = authenticatedUser.user;
1926-
await withRetryTransaction(db, (tx) async {
1947+
final uploaderUserId = await withRetryTransaction(db, (tx) async {
19271948
final packageKey = db.emptyKey.append(Package, id: packageName);
19281949
final package = await tx.lookupOrNull<Package>(packageKey);
19291950
if (package == null) {
@@ -1976,7 +1997,9 @@ class PackageBackend {
19761997
uploaderUser: uploader,
19771998
),
19781999
);
2000+
return uploader.userId;
19792001
});
2002+
await purgeAccountCache(userId: uploaderUserId);
19802003
triggerPackagePostUpdates(
19812004
packageName,
19822005
skipReanalysis: true,

app/lib/shared/redis_cache.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,18 @@ class CachePatterns {
298298
),
299299
)[userId];
300300

301+
Entry<List<String>> userUploaderOfPackages(String userId) => _cache
302+
.withPrefix('user-uploader-of-packages/')
303+
.withTTL(Duration(minutes: 60))
304+
.withCodec(utf8)
305+
.withCodec(json)
306+
.withCodec(
307+
wrapAsCodec(
308+
encode: (List<String> l) => l,
309+
decode: (d) => (d as List).cast<String>(),
310+
),
311+
)[userId];
312+
301313
Entry<String> secretValue(String secretId) => _cache
302314
.withPrefix('secret-value/')
303315
.withTTL(Duration(minutes: 60))

app/test/package/upload_test.dart

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,12 @@ void main() {
110110
testWithProfile(
111111
'successful new package',
112112
fn: () async {
113+
final user = await accountBackend.lookupUserByEmail('user@pub.dev');
114+
expect(
115+
await packageBackend.cachedPackagesWhereUserIsUploader(user.userId),
116+
isEmpty,
117+
);
118+
113119
final dateBeforeTest = clock.now().toUtc();
114120
final pubspecContent = generatePubspecYaml('new_package', '1.2.3');
115121
final message = await createPubApiClient(authToken: userClientToken)
@@ -121,8 +127,6 @@ void main() {
121127
expect(message.success.message, contains('1.2.3'));
122128

123129
// verify state
124-
final user = await accountBackend.lookupUserByEmail('user@pub.dev');
125-
126130
final pkgKey = dbService.emptyKey.append(Package, id: 'new_package');
127131
final package = (await dbService.lookup<Package>([pkgKey])).single!;
128132
expect(package.name, 'new_package');
@@ -143,6 +147,11 @@ void main() {
143147
expect(pv.publisherId, isNull);
144148

145149
await asyncQueue.ongoingProcessing;
150+
expect(
151+
await packageBackend.cachedPackagesWhereUserIsUploader(user.userId),
152+
['new_package'],
153+
);
154+
146155
expect(fakeEmailSender.sentMessages, hasLength(1));
147156
final email = fakeEmailSender.sentMessages.single;
148157
expect(email.recipients.single.email, user.email);

0 commit comments

Comments
 (0)