Skip to content

Instantly share code, notes, and snippets.

@Yama-Tomo
Created June 4, 2021 04:35
Show Gist options
  • Save Yama-Tomo/8af7bb8e0f91e6edd622d25de5ba8ae0 to your computer and use it in GitHub Desktop.
Save Yama-Tomo/8af7bb8e0f91e6edd622d25de5ba8ae0 to your computer and use it in GitHub Desktop.
GCS 上のファイルをアトミックに mv する
import { Bucket, File } from '@google-cloud/storage';
type AtomicFileMvReturnType = [{ src: File; dest: File }, Error | undefined];
const atomicFileMv = async (
bucket: Bucket,
srcPath: string,
destPath: string
): Promise<AtomicFileMvReturnType> => {
const src = bucket.file(srcPath, { generation: 0 });
const dest = bucket.file(destPath, { generation: 0 });
if (!(await src.exists()).pop()) {
return [{ src, dest }, new Error('no such source file')];
}
if ((await dest.exists()).pop()) {
return [{ src, dest }, new Error('already file exists')];
}
const writeableStream = dest.createWriteStream();
const finishWriteDestFile = (resolve: (arg: AtomicFileMvReturnType) => void) => {
src.delete((srcDeleteError) => {
if (!srcDeleteError) {
resolve([{ src, dest }, undefined]);
return;
}
// rollback
dest.delete(() => {
resolve([{ src, dest }, srcDeleteError]);
});
});
};
return new Promise<AtomicFileMvReturnType>((resolve) => {
src.createReadStream().pipe(
writeableStream
.on('finish', () => finishWriteDestFile(resolve))
.on('error', (err) => {
dest.deleteResumableCache();
resolve([{ src, dest }, err]);
})
);
});
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment