我在https Cloud函数(运行Express)中使用Firestore runTransaction
方法。
我想要的是确保如果任何读取或写入失败,则其他事务读取或写入将不会运行,或者在需要时将回滚。
交易
admin.firestore().runTransaction(async (t) => {
const { uid, artworkUid, tagLabel } = req.body;
if (!tagLabel) {
return Promise.reject('Missing parameters: "tagLabel"');
}
if (!artworkUid) {
return Promise.reject('Missing parameters: "artworkUid"');
}
if (tagLabel.length < 3) {
return Promise.reject('The tag must be at least 3 characters long');
}
const [ user, artwork ] = await Promise.all([
getUser(uid),
getArtwork(artworkUid)
]);
return Promise.all([
addArtworkTag({
artwork,
tagLabel,
proposer: user
}, t),
giveXpFor({
user,
action: 'add-artwork-tags',
type: user.can('add-artwork-tags') ? 'effective' : 'temporary'
}, t)
])
})
.catch(err => res.status(403).send(err))
.then(() => res.status(200).send());
您可以看到addArtworkTag
和giveXpFor
函数在参数中使用了t
。
addArtworkTag
export const addArtworkTag = function(params: { artwork: any, tagLabel: string, proposer: ShadraUser }, t?: FirebaseFirestore.Transaction): Promise<any> {
const { artwork, tagLabel, proposer } = params;
if (!artwork || !proposer || typeof tagLabel !== 'string') {
return Promise.reject('Can\'t add the tag. Bad/missing datas');
}
const tag = <any>{
slug: slugify(tagLabel),
label: tagLabel,
status: proposer.can('add-artwork-tags') ? 'validated' : 'proposed',
proposerUid: proposer.uid
};
const tags = artwork.tags || [];
tags.push(tag);
const artworkRef = admin.firestore().doc(`artworks/${artwork.uid}`);
t.set(artworkRef, { tags }, { merge: true });
return Promise.resolve();
}
我的问题是:如果addArtworkTag
函数失败(例如,由于参数错误),我如何中止(甚至回滚)事务,因此不调用giveXpFor
非常感谢
PS:我认为我滥用交易...我应该做的可能只是使用顺序承诺而不是Promise.all,对吗?
答案 0 :(得分:1)
API documentation for runTransaction指出:
如果事务成功完成或被明确中止 (通过updateFunction返回失败的Promise),即Promise updateFunction返回的值将在此处返回。否则,如果 交易失败,相应失败的Promise被拒绝 错误将被返回。
如果交易失败,您要做的就是返回被拒绝的承诺。无论您在该交易中完成了什么,都将被回滚。
答案 1 :(得分:0)
我不确定runTransaction
的功能和查询是否更稳定,应该使用以下多次操作来防止整个脚本崩溃。
try {
//some code
} catch (e) {
//put code here to flag up issues with runTransaction
console.error("Oh No, Not Again said the PlantPot", e);
}