Make syncing/updating photos more resilient to timeouts

This commit is contained in:
Sam Becker 2024-06-17 11:01:19 -05:00
parent 791d020c94
commit 930b80b9f1
4 changed files with 55 additions and 25 deletions

View File

@ -17,6 +17,8 @@ import { getPhotoIds } from '@/photo/db/query';
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db';
import { ReactNode, cache } from 'react';
export const maxDuration = 60;
const getPhotosNearIdCachedCached = cache((photoId: string) =>
getPhotosNearIdCached(photoId, { limit: RELATED_GRID_PHOTOS_TO_SHOW + 2 }));

View File

@ -11,6 +11,7 @@ import { getPhotos, getPhotosMeta } from '@/photo/db/query';
import PhotosLargeInfinite from '@/photo/PhotosLargeInfinite';
export const dynamic = 'force-static';
export const maxDuration = 60;
const getPhotosCached = cache(() => getPhotos({
limit: INFINITE_SCROLL_LARGE_PHOTO_INITIAL,

View File

@ -56,10 +56,10 @@ export const createPhotoAction = async (formData: FormData) =>
const photo = convertFormDataToPhotoDbInsert(formData);
const updatedUrl = await convertUploadToPhoto(
photo.url,
const updatedUrl = await convertUploadToPhoto({
urlOrigin: photo.url,
shouldStripGpsData,
);
});
if (updatedUrl) {
photo.url = updatedUrl;
@ -141,11 +141,11 @@ export const addAllUploadsAction = async ({
addedUploadUrls: addedUploadUrls.join(','),
});
const updatedUrl = await convertUploadToPhoto(
url,
shouldStripGpsData,
const updatedUrl = await convertUploadToPhoto({
urlOrigin: url,
fileBytes,
);
shouldStripGpsData,
});
if (updatedUrl) {
const subhead = 'Adding to database';
stream.update({
@ -179,16 +179,25 @@ export const updatePhotoAction = async (formData: FormData) =>
runAuthenticatedAdminServerAction(async () => {
const photo = convertFormDataToPhotoDbInsert(formData);
let url: string | undefined;
let urlToDelete: string | undefined;
if (photo.hidden && photo.url.includes(photo.id)) {
// Backfill:
// Anonymize storage url on update if necessary by
// re-running image upload transfer logic
url = await convertUploadToPhoto(photo.url);
if (url) { photo.url = url; }
const url = await convertUploadToPhoto({
urlOrigin: photo.url,
shouldDeleteOrigin: false,
});
if (url) {
urlToDelete = photo.url;
photo.url = url;
}
}
await updatePhoto(photo);
await updatePhoto(photo)
.then(async () => {
if (urlToDelete) { await deleteFile(urlToDelete); }
});
revalidatePhoto(photo.id);
@ -307,16 +316,21 @@ export const syncPhotoAction = async (photoId: string) =>
generateResizedImage: AI_TEXT_GENERATION_ENABLED,
});
let urlToDelete: string | undefined;
if (photoFormExif) {
if (photo.url.includes(photo.id) || shouldStripGpsData) {
// Anonymize storage url on update if necessary by
// re-running image upload transfer logic
const url = await convertUploadToPhoto(
photo.url,
shouldStripGpsData,
const url = await convertUploadToPhoto({
urlOrigin: photo.url,
fileBytes,
);
if (url) { photo.url = url; }
shouldStripGpsData,
shouldDeleteOrigin: false,
});
if (url) {
urlToDelete = photo.url;
photo.url = url;
}
}
const {
@ -340,7 +354,11 @@ export const syncPhotoAction = async (photoId: string) =>
{ semanticDescription: aiSemanticDescription },
});
await updatePhoto(photoFormDbInsert);
await updatePhoto(photoFormDbInsert)
.then(async () => {
if (urlToDelete) { await deleteFile(urlToDelete); }
});
revalidateAllKeysAndPaths();
}
}

View File

@ -1,4 +1,5 @@
import {
copyFile,
deleteFile,
generateRandomFileNameForPhoto,
getExtensionFromStorageUrl,
@ -7,24 +8,32 @@ import {
} from '@/services/storage';
import { removeGpsData } from './server';
export const convertUploadToPhoto = async (
urlOrigin: string,
stripGps?: boolean,
fileBytes?: ArrayBuffer,
) => {
export const convertUploadToPhoto = async ({
urlOrigin,
fileBytes,
shouldStripGpsData,
shouldDeleteOrigin = true,
} : {
urlOrigin: string
fileBytes?: ArrayBuffer
shouldStripGpsData?: boolean
shouldDeleteOrigin?: boolean
}) => {
const fileName = generateRandomFileNameForPhoto();
const fileExtension = getExtensionFromStorageUrl(urlOrigin);
const photoPath = `${fileName}.${fileExtension || 'jpg'}`;
if (stripGps) {
if (shouldStripGpsData) {
const fileWithoutGps = await removeGpsData(
fileBytes ?? await fetch(urlOrigin, { cache: 'no-store' })
.then(res => res.arrayBuffer())
);
return putFile(fileWithoutGps, photoPath).then(async url => {
if (url) { await deleteFile(urlOrigin); }
if (url && shouldDeleteOrigin) { await deleteFile(urlOrigin); }
return url;
});
} else {
return moveFile(urlOrigin, photoPath);
return shouldDeleteOrigin
? moveFile(urlOrigin, photoPath)
: copyFile(urlOrigin, photoPath);
}
};