Skip to content

Returning errors from mirai #173

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

Closed
James-G-Hill opened this issue Dec 15, 2024 · 7 comments · Fixed by #176
Closed

Returning errors from mirai #173

James-G-Hill opened this issue Dec 15, 2024 · 7 comments · Fixed by #176

Comments

@James-G-Hill
Copy link

James-G-Hill commented Dec 15, 2024

After reading the documentation and then attempting to implement mirai with shiny::ExtendedTask I am not clear whether I should use stop or rlang::abort within a mirai? I've attempted to do so and an error will be returned so it seems like it should work; however, when I used rlang::abort to return as more complex error the error is changed to a simple error and any extra metadata is removed.

Is this an oversight where mirai is removing the abort metadata or is my whole method wrong?

Edit: I've tested returning an rlang::abort from the shiny::ExtendedTask when not wrapped in mirai and it returns correctly, so it seems that mirai is the key part here.

@James-G-Hill
Copy link
Author

James-G-Hill commented Dec 15, 2024

Having looked at the following I believe the answer is that the mirai will only return the error message string converted to a miraiError?

https://shikokuchuo.net/mirai/reference/mirai.html

@shikokuchuo
Copy link
Member

Hi James, that's correct if you error in a mirai it returns a 'miraiError', which is just a classed character string. It's designed so it's easy to handle without requiring everything to be wrapped in a tryCatch. You can still get the trace back at $trace.back on the 'miraiError' object, but this is also currently just a list of character strings (for ease of handling).

Are you looking for something like the ability for mirai to return a condition that can be re-thrown by rlang::abort() that includes all the context? I haven't looked into integration with rlang yet, but it could be something I consider.

@James-G-Hill
Copy link
Author

Hello, it may be better to explain what I was trying to achieve.

  • My user loads in files of data which are listed in a table with the label 'Unprocessed'.
  • They then choose to process the files in different ways that use long running scripts which I've placed into an ExtendedTask.
  • Just before the script begins running I update the table for the file with 'Processing'.
  • When the ExtendedTask completes successfully I user the returned data to identify which file was processed and update the table to 'Processed'.

However, in some cases I need the ExtendedTask to stop before completion if certain conditions aren't met.
Ideally at that point I would revert the table for the file that failed to process correctly from 'Processing' to 'Unprocessed'.
rlang::abort would allow me to return the name of the file in the metadata so I could identify which row of the table to update.

I've actually managed to implement this solution by placing the file name into the error string that gets returned but that's not particularly robust or flexible as a solution.

It seems to me that being able to return an error with extra metadata in the way that rlang::abort allows would give the user a lot more flexibility around the actions they could take.

It's possible I'm missing something though? I didn't start working with mirai and ExtendedTask until this weekend.

@shikokuchuo
Copy link
Member

Can you share how you’re using rlang::abort() in your non-mirai code? I’ll see if it’s possible to make mirai return metadata in a similar fashion.

@James-G-Hill
Copy link
Author

James-G-Hill commented Dec 22, 2024

Thanks!

Part of my code tries to process an uploaded file within a mirai that's within a shiny::ExtendedTask called process_file. The processing can take a while because the files are large and need to have some computationally expensive checks etc so it's being run in the background while the user can do other tasks. When the task is running there is a table showing all files loaded and their status as either Unprocessed (just after user uploaded), Processing (when the ExtendedTask is running); and Processed when the task is complete.

If the file that was uploaded can't be processed correctly for some reason I might stop the ExtendedTask with something like the below. They key point here is the metadata uploaded_filename along with the filename (a length 1 character vector) I add into the rlang::abort.

if (nrow(dplyr::filter(uploaded_file, .data$is_valid_row_boolean)) < 1) {
  rlang::abort(
    message = "No valid rows in uploaded file.",
    class = "error",
    uploaded_filename = var_containing_name_of_uploaded_file
  )
}

Then later, in an observe that monitors for an update to the ExtendedTask status I need to handle the result. Whether the processing was able to complete or not, I need to update the table showing the status of each file. If I threw an error like the one above I want to change the table to show Unprocessed again; if the processing completed then I need to update the table to show Processed. The rlang::abort would be used to pass the name of the file that didn't succeed in being processed so I could make the update to the table when handling the error.

table_of_uploaded_files is a reactiveVal.

dta <-
  tryCatch(
    process_data$result(),
    error =
      \(e) {
        table_of_uploaded_files(
          dplyr::mutate(
            table_of_uploaded_files(),
            "processing_status" =
              replace(
                .data$processing_status,
                table_of_uploaded_files()$name == e$uploaded_filename,
                "Unprocessed"
              )
          )
        )
        NULL
      }
  )

shiny::req(dta)

# If dta is not NULL then proceed to work with the file

This is a very stripped down version of the code; in real use cases it would be handy to include even more metadata within the rlang::abort; not just the uploaded_filename.

@shikokuchuo
Copy link
Member

@James-G-Hill thanks for the example. I'm about to merge a PR which causes a miraiError to be returned with the original condition object. So in your case, you can use rlang::abort() appending custom metadata, and that will be available on the 'miraiError' using the $ accessor.

In case you need something more, feel free to re-open.

@James-G-Hill
Copy link
Author

Hello @shikokuchuo , thanks for that. I'm on leave from work for another week or so but will test this out on my return.

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 a pull request may close this issue.

2 participants