Skip to content

Commit

Permalink
[lib] Use batch Blob service endpoints in processHolders action
Browse files Browse the repository at this point in the history
Summary:
Address [[ https://linear.app/comm/issue/ENG-9355/update-processholdersaction-to-use-batched-blob-endpoints | ENG-9355 ]].
When processing holders, we can make 1-2 batch Blob HTTP calls instead of M+N calls for every single processed holder.

Depends on D13656

Test Plan: Start a DM thread, set image thread avatar, then reset back to emoji. With Redux devtools and console logs verify that actions are successful.

Reviewers: kamil, tomek

Reviewed By: kamil

Subscribers: ashoat

Differential Revision: https://phab.comm.dev/D13657
  • Loading branch information
barthap committed Oct 10, 2024
1 parent 4ca6710 commit 6d07670
Showing 1 changed file with 30 additions and 42 deletions.
72 changes: 30 additions & 42 deletions lib/actions/holder-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import invariant from 'invariant';
import * as React from 'react';

import blobService from '../facts/blob-service.js';
import {
type AuthMetadata,
IdentityClientContext,
Expand All @@ -14,8 +13,9 @@ import type {
} from '../types/holder-types.js';
import { toBase64URL } from '../utils/base64.js';
import {
makeBlobServiceEndpointURL,
generateBlobHolder,
assignMultipleHolders,
removeMultipleHolders,
} from '../utils/blob-service.js';
import { useDispatchActionPromise } from '../utils/redux-promise-utils.js';
import { useSelector } from '../utils/redux-utils.js';
Expand Down Expand Up @@ -50,8 +50,6 @@ type BlobServiceActionsResult = {
+failed: MultipleBlobHolders,
};

// This function can be simplified when batch holders operations
// are implemented on Blob Service
async function performBlobServiceHolderActions(
action: 'establish' | 'remove',
inputs: MultipleBlobHolders,
Expand All @@ -61,53 +59,43 @@ async function performBlobServiceHolderActions(
return { succeeded: [], failed: [] };
}

const endpoint =
action === 'establish'
? blobService.httpEndpoints.ASSIGN_HOLDER
: blobService.httpEndpoints.DELETE_BLOB;
const endpointURL = makeBlobServiceEndpointURL(endpoint);
const defaultHeaders = createDefaultHTTPRequestHeaders(authMetadata);
const blobServiceCall =
action === 'establish' ? assignMultipleHolders : removeMultipleHolders;

const requestInputs = inputs.map(({ blobHash, ...rest }) => ({
...rest,
blobHash: toBase64URL(blobHash),
}));
const response = await blobServiceCall(requestInputs, defaultHeaders);
if (response.result === 'success') {
return { succeeded: inputs, failed: [] };
}
if (response.result === 'error') {
return { succeeded: [], failed: inputs };
}

const promises = inputs.map(async input => {
const blobHash = toBase64URL(input.blobHash);
try {
const response = await fetch(endpointURL, {
method: endpoint.method,
body: JSON.stringify({
holder: input.holder,
blob_hash: blobHash,
}),
headers: {
...defaultHeaders,
'content-type': 'application/json',
},
});
const holderAlreadyEstablishedResponse =
action === 'establish' && response.status === 409;
if (response.ok || holderAlreadyEstablishedResponse) {
return { ...input, success: true };
}
return { ...input, success: false };
} catch (e) {
return { ...input, success: false };
}
});
const failedRequestsSet = new Set(
response.failedRequests.map(({ blobHash, holder }) =>
JSON.stringify({ blobHash, holder }),
),
);

const results = await Promise.all(promises);
const succeeded = [],
failed = [];
for (const { success, ...holderEntry } of results) {
if (success) {
succeeded.push(holderEntry);
for (const item of inputs) {
const stringifiedItem = JSON.stringify({
blobHash: toBase64URL(item.blobHash),
holder: item.holder,
});
if (failedRequestsSet.has(stringifiedItem)) {
failed.push(item);
} else {
failed.push(holderEntry);
succeeded.push(item);
}
}

return {
succeeded,
failed,
};
return { succeeded, failed };
}

async function processHoldersAction(
Expand Down

0 comments on commit 6d07670

Please sign in to comment.