Proposed High Level Outline for Deprecating the ActorStack - samvera/hyrax GitHub Wiki
The goal of this refactor is to remove the case logic around the create_work
and update_work
methods in the Hyrax::WorksControllerBehavior
module. Aspirationally, we would factor away the actor stack in favor of change sets (form
) and transactions.
Below is an example of the two logic paths, one for ActiveFedora::Base
objects and one Valkyrie` objects.
# See ./app/controllers/concerns/hyrax/works_controller_behavior.rb
def create_work
case curation_concern
when ActiveFedora::Base
# I copied the following two lines to provide more context for the example
actor_environment = Actors::Environment.new(curation_concern, current_ability, attributes_for_actor)
actor = Hyrax::CurationConcern.actor
actor.create(actor_environment)
else
# I copied the following two lines to provide more context for the example
transactions = Hyrax::Transactions::Container
form = work_form_service.build(curation_concern, current_ability, self)
@curation_concern = form.validate(params[hash_key_for_curation_concern]) &&
transactions['change_set.create_work'].call(form).value!
end
end
For ActiveFedora::Base
we build the actor_environment
, analogue to Rack middleware’s env
. With that environment we tell the actor to perform a create
. The actor is responsible for both data validation and performing a variety of side-effect producing processes to manipulate the state of the form attributes and the model.
Multiple actors compose the stack (see ./app/services/hyrax/default_middleware_stack.rb
). Each actor implements a create
and update
method that receives the actor_environment
.
The pattern of each actor is roughly as follows:
- Do something before calling the next actor in the stack a. Validation? b. Alter params? c. Make data changes? d. Launch a job? e. It all depends on the implementation
- Call the next step in the actor stack
- Do something after calling the next actor in the stack a. As step one, it could be just about anything
With multiple actors in the stack, as we work our way down the stack, we stop when the actor returns from the called method; It could stop because of an error or because validation failed or some other reason.
It should be noted that many "states" might change in the process. The actor stack as implemented, mutates parameters, the given curation_concern, and the persistence and indexing layers. There is minimal transactionality surrounding this behavior, so we can easily end up with partially applied processes.
This loose pattern allows for the flexibility of before and after behavior, but creates an opaque process. To know what's happening, you need to follow the stack, and look at what happens both before and after calling the next actor.
For the other case (e.g. not ActiveFedora::Base
), we separate the validations (e.g. form.validate
)from the state changing operations (e.g. transactions[‘change_set.create_work’].call(form)
).
Aspirationally, we want the form.validate
to perform the same-ish validations as the actor stack steps. Likewise, when we use the named transaction (e.g. transactions[‘change_set.create_work’]
) we want to perform the same-ish state changing processes as the actor stack steps.
From ./app/services/hyrax/default_middleware_stack.rb
we have the following actors:
Hyrax::Actors::OptimisticLockValidator
Hyrax::Actors::CreateWithRemoteFilesActor
Hyrax::Actors::CreateWithFilesActor
Hyrax::Actors::CollectionsMembershipActor
Hyrax::Actors::AddToWorkActor
Hyrax::Actors::AttachMembersActor
Hyrax::Actors::ApplyOrderActor
Hyrax::Actors::DefaultAdminSetActor
Hyrax::Actors::InterpretVisibilityActor
Hyrax::Actors::TransferRequestActor
Hyrax::Actors::ApplyPermissionTemplateActor
Hyrax::Actors::CleanupFileSetsActor
Hyrax::Actors::CleanupTrophiesActor
Hyrax::Actors::FeaturedWorkActor
Hyrax::Actors::ModelActor
Hyrax::Actors::InitializeWorkflowActor
The above actors in the actor stack need to be closely read, extracting logic for validation (e.g. form.validate
) and applying changes to the data (e.g. transaction
). Going forward, I believe there are two primary epic issues that need crafting:
- Extract ActorStack validations
- Extract ActorStack transactions
As we don't know how downstream adopters modify the stack, care must be taken to provide a clear forward path.