From ac567f7e71381b147b6da98c0429b6fa61a16534 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Fri, 18 Mar 2022 10:17:20 +0800 Subject: [PATCH 1/8] retry max three times if update is conflicted --- packages/api/src/elastic/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/api/src/elastic/index.ts b/packages/api/src/elastic/index.ts index 65a645bc5..c2acfdce7 100644 --- a/packages/api/src/elastic/index.ts +++ b/packages/api/src/elastic/index.ts @@ -201,6 +201,7 @@ export const updatePage = async ( }, }, refresh: ctx.refresh, + retry_on_conflict: 3, }) if (body.result !== 'updated') return false From 9d8d2e40d78f67a8403ca41a188f659980774eb1 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Fri, 18 Mar 2022 10:29:01 +0800 Subject: [PATCH 2/8] reduce time to save reading progress in elastic update --- packages/api/src/resolvers/article/index.ts | 25 ++++++++++----------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/packages/api/src/resolvers/article/index.ts b/packages/api/src/resolvers/article/index.ts index 71b372a0f..e1337f7e8 100644 --- a/packages/api/src/resolvers/article/index.ts +++ b/packages/api/src/resolvers/article/index.ts @@ -707,9 +707,9 @@ export const saveArticleReadingProgressResolver = authorized< { input: { id, readingProgressPercent, readingProgressAnchorIndex } }, { claims: { uid }, pubsub } ) => { - const userArticleRecord = await getPageByParam({ userId: uid, _id: id }) + const page = await getPageByParam({ userId: uid, _id: id }) - if (!userArticleRecord) { + if (!page) { return { errorCodes: [SaveArticleReadingProgressErrorCode.NotFound] } } @@ -725,26 +725,25 @@ export const saveArticleReadingProgressResolver = authorized< // be greater than the current reading progress. const shouldUpdate = readingProgressPercent === 0 || - (userArticleRecord.readingProgressPercent || 0) < - readingProgressPercent || - (userArticleRecord.readingProgressAnchorIndex || 0) < - readingProgressAnchorIndex + page.readingProgressPercent < readingProgressPercent || + page.readingProgressAnchorIndex < readingProgressAnchorIndex - const updatedArticle = Object.assign(userArticleRecord, { + const updatedPart = { readingProgressPercent: shouldUpdate ? readingProgressPercent - : userArticleRecord.readingProgressPercent, + : page.readingProgressPercent, readingProgressAnchorIndex: shouldUpdate ? readingProgressAnchorIndex - : userArticleRecord.readingProgressAnchorIndex, - }) + : page.readingProgressAnchorIndex, + } - shouldUpdate && (await updatePage(id, updatedArticle, { pubsub, uid })) + shouldUpdate && (await updatePage(id, updatedPart, { pubsub, uid })) return { updatedArticle: { - ...updatedArticle, - isArchived: !!updatedArticle.archivedAt, + ...page, + ...updatedPart, + isArchived: !!page.archivedAt, }, } } From 77050905a5b9fa6c683f729fe1c487f080a4a94c Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Fri, 18 Mar 2022 10:39:11 +0800 Subject: [PATCH 3/8] retry max three times if update labels is conflicted --- packages/api/src/elastic/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/api/src/elastic/index.ts b/packages/api/src/elastic/index.ts index c2acfdce7..3ec074933 100644 --- a/packages/api/src/elastic/index.ts +++ b/packages/api/src/elastic/index.ts @@ -238,6 +238,7 @@ export const addLabelInPage = async ( }, }, refresh: ctx.refresh, + retry_on_conflict: 3, }) return body.result === 'updated' From 1218bb0afdc9ceabb45e803ecb68a87648167662 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Fri, 18 Mar 2022 12:20:45 +0800 Subject: [PATCH 4/8] use lodash debounce the api call to save reading progress --- .../components/templates/article/Article.tsx | 56 +++++++++++-------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/packages/web/components/templates/article/Article.tsx b/packages/web/components/templates/article/Article.tsx index 60bbe1ff1..8f13db9ab 100644 --- a/packages/web/components/templates/article/Article.tsx +++ b/packages/web/components/templates/article/Article.tsx @@ -1,21 +1,22 @@ import { Box } from './../../../components/elements/LayoutPrimitives' import { useReadingProgressAnchor } from '../../../lib/hooks/useReadingProgressAnchor' import { - useScrollWatcher, ScrollOffsetChangeset, + useScrollWatcher, } from '../../../lib/hooks/useScrollWatcher' import { - useRef, - useState, - useEffect, MutableRefObject, useCallback, + useEffect, + useMemo, + useRef, + useState, } from 'react' import { articleReadingProgressMutation } from '../../../lib/networking/mutations/articleReadingProgressMutation' import { Tweet } from 'react-twitter-widgets' import { render } from 'react-dom' import { isDarkTheme } from '../../../lib/themeUpdater' -import useDebounce from '../../../lib/hooks/useDebounce' +import { debounce } from 'lodash' export type ArticleProps = { articleId: string @@ -28,7 +29,9 @@ export type ArticleProps = { export function Article(props: ArticleProps): JSX.Element { const highlightTheme = isDarkTheme() ? 'dark' : 'default' - const [readingProgress, setReadingProgress] = useState(props.initialReadingProgress) + const [readingProgress, setReadingProgress] = useState( + props.initialReadingProgress + ) const [readingAnchorIndex, setReadingAnchorIndex] = useState( props.initialAnchorIndex @@ -41,35 +44,38 @@ export function Article(props: ArticleProps): JSX.Element { useReadingProgressAnchor(articleContentRef, setReadingAnchorIndex) - const debouncedReadingProgress = useDebounce(readingProgress, 1000); + const debouncedReadingProgress = useMemo( + () => + debounce(async () => { + if (!readingProgress) return + + await articleReadingProgressMutation({ + id: props.articleId, + readingProgressPercent: readingProgress, + readingProgressAnchorIndex: readingAnchorIndex, + }) + }, 3000), + [readingProgress] + ) useEffect(() => { ;(async () => { - if (!debouncedReadingProgress) return - await articleReadingProgressMutation({ - id: props.articleId, - readingProgressPercent: debouncedReadingProgress, - readingProgressAnchorIndex: readingAnchorIndex, - }) + await debouncedReadingProgress() })() // We don't react to changes to readingAnchorIndex we // only care about the progress (scroll position) changed. // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ - props.articleId, - debouncedReadingProgress, - readingAnchorIndex, - ]) + }, [props.articleId, readingProgress, readingAnchorIndex]) // Post message to webkit so apple app embeds get progress updates useEffect(() => { if (typeof window?.webkit != 'undefined') { window.webkit.messageHandlers.readingProgressUpdate?.postMessage({ - progress: debouncedReadingProgress, + progress: readingProgress, }) } - }, [readingProgress, debouncedReadingProgress]) + }, [readingProgress]) const setScrollWatchedElement = useScrollWatcher( (changeset: ScrollOffsetChangeset) => { @@ -152,9 +158,15 @@ export function Article(props: ArticleProps): JSX.Element { } if (props.scrollElementRef.current) { - props.scrollElementRef.current?.scroll(0, calculateOffset(anchorElement)) + props.scrollElementRef.current?.scroll( + 0, + calculateOffset(anchorElement) + ) } else { - window.document.documentElement.scroll(0, calculateOffset(anchorElement)) + window.document.documentElement.scroll( + 0, + calculateOffset(anchorElement) + ) } } }, [ From 365859bb6301ef04eebfa8310a0576e9db41878a Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Fri, 18 Mar 2022 12:30:06 +0800 Subject: [PATCH 5/8] import lodash --- packages/web/package.json | 1 + yarn.lock | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/packages/web/package.json b/packages/web/package.json index 34236e76d..49a6a9737 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -50,6 +50,7 @@ "@types/cookie": "^0.4.1", "@types/diff-match-patch": "^1.0.32", "@types/jest": "^27.0.2", + "@types/lodash.debounce": "^4.0.6", "@types/react": "17.0.2", "@types/react-dom": "^17.0.2", "@types/segment-analytics": "^0.0.34", diff --git a/yarn.lock b/yarn.lock index e99e3552b..bd1b1dd0f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5443,6 +5443,18 @@ "@types/interpret" "*" "@types/node" "*" +"@types/lodash.debounce@^4.0.6": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@types/lodash.debounce/-/lodash.debounce-4.0.6.tgz#c5a2326cd3efc46566c47e4c0aa248dc0ee57d60" + integrity sha512-4WTmnnhCfDvvuLMaF3KV4Qfki93KebocUF45msxhYyjMttZDQYzHkO639ohhk8+oco2cluAFL3t5+Jn4mleylQ== + dependencies: + "@types/lodash" "*" + +"@types/lodash@*": + version "4.14.180" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.180.tgz#4ab7c9ddfc92ec4a887886483bc14c79fb380670" + integrity sha512-XOKXa1KIxtNXgASAnwj7cnttJxS4fksBRywK/9LzRV5YxrF80BXZIGeQSuoESQ/VkUj30Ae0+YcuHc15wJCB2g== + "@types/long@^4.0.0", "@types/long@^4.0.1": version "4.0.1" resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9" From 17edc482f6b03703a59deb28db9523e36d812b89 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Fri, 18 Mar 2022 14:06:58 +0800 Subject: [PATCH 6/8] update debounce timeout to be 2 seconds --- .../components/templates/article/Article.tsx | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/packages/web/components/templates/article/Article.tsx b/packages/web/components/templates/article/Article.tsx index 8f13db9ab..60de8c24b 100644 --- a/packages/web/components/templates/article/Article.tsx +++ b/packages/web/components/templates/article/Article.tsx @@ -1,4 +1,4 @@ -import { Box } from './../../../components/elements/LayoutPrimitives' +import { Box } from '../../elements/LayoutPrimitives' import { useReadingProgressAnchor } from '../../../lib/hooks/useReadingProgressAnchor' import { ScrollOffsetChangeset, @@ -44,29 +44,37 @@ export function Article(props: ArticleProps): JSX.Element { useReadingProgressAnchor(articleContentRef, setReadingAnchorIndex) - const debouncedReadingProgress = useMemo( + const debouncedSetReadingProgress = useMemo( () => - debounce(async () => { - if (!readingProgress) return - - await articleReadingProgressMutation({ - id: props.articleId, - readingProgressPercent: readingProgress, - readingProgressAnchorIndex: readingAnchorIndex, - }) - }, 3000), - [readingProgress] + debounce((readingProgress: number) => { + console.log('setReadingProgress', readingProgress) + setReadingProgress(readingProgress) + }, 2000), + [] ) + // Stop the invocation of the debounced function + // after unmounting + useEffect(() => { + return () => { + debouncedSetReadingProgress.cancel() + } + }, []) + useEffect(() => { ;(async () => { - await debouncedReadingProgress() + if (!readingProgress) return + await articleReadingProgressMutation({ + id: props.articleId, + readingProgressPercent: readingProgress, + readingProgressAnchorIndex: readingAnchorIndex, + }) })() // We don't react to changes to readingAnchorIndex we // only care about the progress (scroll position) changed. // eslint-disable-next-line react-hooks/exhaustive-deps - }, [props.articleId, readingProgress, readingAnchorIndex]) + }, [props.articleId, readingProgress]) // Post message to webkit so apple app embeds get progress updates useEffect(() => { @@ -85,13 +93,13 @@ export function Article(props: ArticleProps): JSX.Element { (changeset.current.y + scrollContainer.clientHeight) / scrollContainer.scrollHeight - setReadingProgress(newReadingProgress * 100) + debouncedSetReadingProgress(newReadingProgress * 100) } else if (window && window.document.scrollingElement) { const newReadingProgress = window.scrollY / window.document.scrollingElement.scrollHeight const adjustedReadingProgress = newReadingProgress > 0.92 ? 1 : newReadingProgress - setReadingProgress(adjustedReadingProgress * 100) + debouncedSetReadingProgress(adjustedReadingProgress * 100) } }, 1000 From 4c535147f1cfa56c6284c8359d12935479df88c0 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Fri, 18 Mar 2022 14:50:08 +0800 Subject: [PATCH 7/8] round reading progress to 100% if more than that round reading progress to 100% if more than that round reading progress to 100% if more than that --- packages/web/components/templates/article/Article.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/web/components/templates/article/Article.tsx b/packages/web/components/templates/article/Article.tsx index 60de8c24b..f02be67c2 100644 --- a/packages/web/components/templates/article/Article.tsx +++ b/packages/web/components/templates/article/Article.tsx @@ -66,7 +66,8 @@ export function Article(props: ArticleProps): JSX.Element { if (!readingProgress) return await articleReadingProgressMutation({ id: props.articleId, - readingProgressPercent: readingProgress, + // round reading progress to 100% if more than that + readingProgressPercent: readingProgress > 100 ? 100 : readingProgress, readingProgressAnchorIndex: readingAnchorIndex, }) })() From 705ebffff3f99428c718aa45296b48874bc7c9fb Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Fri, 18 Mar 2022 17:08:47 +0800 Subject: [PATCH 8/8] only refresh items on home feed --- .../components/templates/homeFeed/HomeFeedContainer.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/web/components/templates/homeFeed/HomeFeedContainer.tsx b/packages/web/components/templates/homeFeed/HomeFeedContainer.tsx index 7b04fabab..36c2371c4 100644 --- a/packages/web/components/templates/homeFeed/HomeFeedContainer.tsx +++ b/packages/web/components/templates/homeFeed/HomeFeedContainer.tsx @@ -206,9 +206,12 @@ export function HomeFeedContainer(props: HomeFeedContainerProps): JSX.Element { if (activeCardId && !alreadyScrolled.current) { scrollToActiveCard(activeCardId) alreadyScrolled.current = true - } - if (activeItem) { - performActionOnItem('refresh', activeItem) + + if (activeItem) { + console.log('refreshing') + // refresh items on home feed + performActionOnItem('refresh', activeItem) + } } }, [activeCardId, scrollToActiveCard])