Вопрос

I'll break this post into two parts, because I'm trying to abstract the concept, but will explain my implementation at the end.

I have two workflows, Workflow A and Workflow B. Part of Workflow B relies on the results of Workflow A. They can be executed sequentially and work as intended, but I want to pipeline them. I want the first half of B to occur parallel to A. That means that I need to at a certain point in B wait for the completion results of A. What would be the best way to handle this?


As for my actual use case, I'm writing an update script, and it is composed of two parts.

A.) Uninstall some existing (out of date) applications

B.) Download and reinstall them

The Download portion can occur in parallel with the removal part. I want to call both at the same time, but have B wait to reinstall the apps until after A has successfully removed the older versions. What would be the best way to do this?


What I've considered

Breaking up the "Download" and "reinstall" portion of B into two parts. This makes sense from the perspective of pipelining them, but if I make the "Reinstall" portion publicly available it will cause issues if the "download" portion isn't run first.

Passing the Task object that encompasses the the "uninstall some existing applications" portion to the "download and reinstall" portion and waiting on it's completion, which satisfies dependency injection (as in, process B depends on the completion of Process A) but that seems messy

Это было полезно?

Решение

To formalize the condition (invariant) at the moment the synchronization happens:

  • Installation of the new application is allowed to start, if all of these are true:
    • That there is no obstruction caused by a pre-existing installation of the (old) application, or specifically:
      • The old application was not running
      • Neither the installer nor uninstaller specific to the old application was running
      • The installation paths (targets) for the old application seems not obstructed
    • That the installation package for the new application is ready to use, or specifically:
      • That it has been downloaded
      • That the downloaded file has good checksum (not truncated)

To prevent your API users (clueless or malicious, depending on their mood) from misusing the "Reinstall" portion, you can simply re-check the requirement as described above.


I would prefer the separation of the downloading and reinstalling steps.

I'm not sure why you would consider the downloading and reinstalling to be conceptually more closely related. My guess is that, you might be thinking that uninstallation is a conditional task that depends on whether a previous installation exists.

I can offer a counterargument to show that downloading can also be a conditional task. Suppose the user has already run the scripts once, such that the latest installation package has already been downloaded. However, the user cancelled the installation, but decided to keep the downloaded installation package. Now, if the user re-runs the script, neither the uninstalltion nor the download should happen. The script should jump right into installing the new application.


If you intend to make one of them the Task (i.e. also known as a Future in other languages), it is better to make the simpler one to be the Task.

In this case, downloading a file is the simpler task, because the result can be expressed cleanly as either succeeded (the file is there and its checksum is valid), or failed (for any reasons, including no internet connection or timeouts). The only unclean part about downloading a file is cleaning it up afterwards.

Лицензировано под: CC-BY-SA с атрибуция
scroll top