Skip to content

Commit

Permalink
Avoid race conditions when queueing a story for download
Browse files Browse the repository at this point in the history
  • Loading branch information
josh-signal committed Aug 11, 2022
1 parent 0a81376 commit 584b39b
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 4 deletions.
42 changes: 40 additions & 2 deletions ts/state/ducks/stories.ts
Expand Up @@ -52,6 +52,7 @@ import { viewedReceiptsJobQueue } from '../../jobs/viewedReceiptsJobQueue';
export type StoryDataType = {
attachment?: AttachmentType;
messageId: string;
startedDownload?: boolean;
} & Pick<
MessageAttributesType,
| 'canReplyToStory'
Expand Down Expand Up @@ -92,6 +93,7 @@ export type StoriesStateType = {
const DOE_STORY = 'stories/DOE';
const LOAD_STORY_REPLIES = 'stories/LOAD_STORY_REPLIES';
const MARK_STORY_READ = 'stories/MARK_STORY_READ';
const QUEUE_STORY_DOWNLOAD = 'stories/QUEUE_STORY_DOWNLOAD';
const REPLY_TO_STORY = 'stories/REPLY_TO_STORY';
export const RESOLVE_ATTACHMENT_URL = 'stories/RESOLVE_ATTACHMENT_URL';
const STORY_CHANGED = 'stories/STORY_CHANGED';
Expand All @@ -116,6 +118,11 @@ type MarkStoryReadActionType = {
payload: string;
};

type QueueStoryDownloadActionType = {
type: typeof QUEUE_STORY_DOWNLOAD;
payload: string;
};

type ReplyToStoryActionType = {
type: typeof REPLY_TO_STORY;
payload: MessageAttributesType;
Expand Down Expand Up @@ -155,6 +162,7 @@ export type StoriesActionType =
| MessageChangedActionType
| MessageDeletedActionType
| MessagesAddedActionType
| QueueStoryDownloadActionType
| ReplyToStoryActionType
| ResolveAttachmentUrlActionType
| StoryChangedActionType
Expand Down Expand Up @@ -431,7 +439,7 @@ function queueStoryDownload(
void,
RootStateType,
unknown,
NoopActionType | ResolveAttachmentUrlActionType
NoopActionType | QueueStoryDownloadActionType | ResolveAttachmentUrlActionType
> {
return async (dispatch, getState) => {
const { stories } = getState().stories;
Expand Down Expand Up @@ -477,7 +485,11 @@ function queueStoryDownload(
return;
}

if (isDownloading(attachment)) {
// isDownloading checks for the downloadJobId which is set by
// queueAttachmentDownloads but we optimistically set story.startedDownload
// in redux to prevent race conditions from queuing up multiple attachment
// downloads before the attachment save takes place.
if (isDownloading(attachment) || story.startedDownload) {
return;
}

Expand All @@ -488,7 +500,13 @@ function queueStoryDownload(
// completed attachment download.
message.set({ storyReplyContext: undefined });

dispatch({
type: QUEUE_STORY_DOWNLOAD,
payload: storyId,
});

await queueAttachmentDownloads(message.attributes);
return;
}

dispatch({
Expand Down Expand Up @@ -1205,5 +1223,25 @@ export function reducer(
};
}

if (action.type === QUEUE_STORY_DOWNLOAD) {
const storyIndex = state.stories.findIndex(
story => story.messageId === action.payload
);

if (storyIndex < 0) {
return state;
}

const existingStory = state.stories[storyIndex];

return {
...state,
stories: replaceIndex(state.stories, storyIndex, {
...existingStory,
startedDownload: true,
}),
};
}

return state;
}
4 changes: 2 additions & 2 deletions ts/test-electron/state/ducks/stories_test.ts
Expand Up @@ -202,8 +202,8 @@ describe('both/state/ducks/stories', () => {
await queueStoryDownload(storyId)(dispatch, getState, null);

sinon.assert.calledWith(dispatch, {
type: 'NOOP',
payload: null,
type: 'stories/QUEUE_STORY_DOWNLOAD',
payload: storyId,
});
});
});
Expand Down

0 comments on commit 584b39b

Please sign in to comment.