Skip to content

Enable cancellation for Lift exports #3664

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 17 commits into
base: master
Choose a base branch
from
Draft

Enable cancellation for Lift exports #3664

wants to merge 17 commits into from

Conversation

andracc
Copy link
Collaborator

@andracc andracc commented Mar 6, 2025

Resolves #3254

This change is Reviewable

Copy link

codecov bot commented Mar 6, 2025

Codecov Report

Attention: Patch coverage is 48.57143% with 36 lines in your changes missing coverage. Please review.

Project coverage is 72.97%. Comparing base (6ed1ef7) to head (8cfe3ce).

Files with missing lines Patch % Lines
Backend/Controllers/LiftController.cs 54.54% 10 Missing ⚠️
Backend/Services/PermissionService.cs 0.00% 7 Missing ⚠️
...onents/ProjectExport/Redux/ExportProjectActions.ts 0.00% 6 Missing ⚠️
src/components/ProjectExport/ExportButton.tsx 61.53% 4 Missing and 1 partial ⚠️
Backend/Services/LiftService.cs 77.77% 3 Missing and 1 partial ⚠️
...onents/ProjectExport/Redux/ExportProjectReducer.ts 0.00% 3 Missing ⚠️
src/components/ProjectExport/DownloadButton.tsx 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3664      +/-   ##
==========================================
- Coverage   73.18%   72.97%   -0.21%     
==========================================
  Files         285      285              
  Lines       10673    10721      +48     
  Branches     1332     1334       +2     
==========================================
+ Hits         7811     7824      +13     
- Misses       2467     2500      +33     
- Partials      395      397       +2     
Flag Coverage Δ
backend 82.14% <55.31%> (-0.32%) ⬇️
frontend 65.77% <34.78%> (-0.14%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

</span>
</Tooltip>
<>
<Tooltip title={!exports ? t("projectExport.cannotExportEmpty") : ""}>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this tooltip will never be active when the reset button is also active, but it feels odd to have it around the reset button too, especially since we might want to give the reset button its own tooltip.

@imnasnainaec imnasnainaec linked an issue Mar 12, 2025 that may be closed by this pull request
// cancelled


// note cancelled
_liftExports.Remove(userId);
_liftExports.Add(userId, filePath);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@imnasnainaec the Dictionary class is not thread safe and the more you use it the more likely you are to run into trouble. I would swap it out for Concurrent Dictionary which is thread safe.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hahn-kev Ah, thanks for pointing that out @hahn-kev. Might we also need to use a lock if two different threads are checking then updating the same dictionary entry?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could do that instead, but it would be much simpler to use the correct type. It's also much more reliable as you have to be careful with locks to not access the object outside of the lock.

Copy link
Collaborator

@imnasnainaec imnasnainaec left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 2 of 9 files at r2, 3 of 7 files at r5, all commit messages.
Reviewable status: 5 of 14 files reviewed, 4 unresolved discussions (waiting on @andracc)


Backend/Controllers/LiftController.cs line 289 at r5 (raw file):

        /// <summary> Cancels project export </summary>
        /// <returns> ProjectId, if cancel successful </returns>
        [HttpGet("cancelExport", Name = "CancelLiftExport")]

Use all-lowercase urls:"cancelExport" -> "cancelexport"


Backend/Controllers/LiftController.cs line 377 at r5 (raw file):

                    await _notifyService.Clients.All.SendAsync(CombineHub.DownloadReady, userId);
                }
                return true;

return proceed; might make more sense, even if we're not using that return value.


Backend/Services/LiftService.cs line 155 at r5 (raw file):

                {
                    _liftExports.TryAdd(userId, (InProgress, exportId));
                }

I think you could use .AddOrUpdate (rather than .TryRemove and .TryAdd) to avoid a lock in SetExportInProgress (and possibly elsewhere).

This comment has been minimized.

Copy link
Collaborator

@imnasnainaec imnasnainaec left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed all commit messages.
Reviewable status: 5 of 17 files reviewed, 3 unresolved discussions (waiting on @andracc)


Backend/Services/LiftService.cs line 138 at r6 (raw file):

        /// <summary> Store status that a user's export is cancelled. </summary>
        public void SetCancelExport(string userId)

Since SetCancelExport isn't setting anything, something like CancelExport or ClearExportInProgress would be more accurate.


Backend/Services/LiftService.cs line 144 at r6 (raw file):

        /// <summary> Store status that a user's export is in-progress. </summary>
        public void SetExportInProgress(string userId, bool isInProgress, string exportId)

Now that we have a function to cancel exports, that can be used instead of this with isInProgress = false, so we can drop that middle bool param (and add a check to throw an error if exportId is empty).

Copy link
Collaborator

@imnasnainaec imnasnainaec left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dismissed @hahn-kev from a discussion.
Reviewable status: 5 of 17 files reviewed, 3 unresolved discussions (waiting on @andracc)


src/components/ProjectExport/Redux/ExportProjectReduxTypes.ts line 2 at r9 (raw file):

export enum ExportStatus {
  Canceling = "CANCELING",

I'm not sure why/whether we need this added status option for the Redux state or if it's sufficient to handle the canceling state within the ExportButton component.


Backend/Services/PermissionService.cs line 144 at r9 (raw file):

                return "";
            }
            return exportId;

Can simplify to return request.TraceIdentifier ?? "";


src/components/ProjectExport/ExportButton.tsx line 25 at r9 (raw file):

export default function ExportButton(props: ExportButtonProps): ReactElement {
  const dispatch = useAppDispatch();
  const [canceling, setCanceling] = useState(false);

This component state canceling should only be necessary if we get rid of the ExportStatus.Canceling in the Redux state. If we keep that, then you should be able to use status === ExportStatus.Canceling in place of canceling.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Export stuck for multiple testers' accounts on QA
3 participants