2

Subj - how could I allow\disallow actions in my system based on the state of another external system (I have access to it's state via the shared DB table)? I can get the state of another system almost immediately, another system is like a state machine with some states like 'running', 'maintenance', 'initializing' etc.

For example there are some of my commands and queries

  1. DeleteExternalSystem(systemId)
  2. ChangeStateOfExternalSystem(newState)
  3. DoSomethingWithExternalSystem1(systemId, param)
  4. DoSomethingWithExternalSystem2(systemId, param)

If external system is in state 'initializing' I want to prohibit calling of DeleteExternalSystem and ChangeStateOfExternalSystem, but allow to call DoSomethingWithExternalSystem1 and like so many other cases. Some of them should also return OK status for some specific states without actually executing underlying method. Also important point - state of external system could be changed inside my commands sometimes. For example command could switch system from the state 'maintenance' to state 'running' and so on.

Could someone suggest me the preffered approach to this problem? Maybe there are some patterns which could be used to bypass my problem?

1 Answer 1

1

Prohibit calling how?

If we were talking about some GUI you could mean graying out buttons until the state they require is reached. But now you have to constantly poll the other system state to keep the enabled/disabled state of your buttons current. If that's what you do you'll want to see if you can pack all the states you care about into one simple message to minimize the traffic this will cause. But even that will occasionally allow button presses at the wrong time.

If we're talking about commands a user can just type at a command line then you really can't disable them.

What you can do is remember these are commands. Not guarantees.

No command ever designed ensures obedience. How obedience, or lack thereof, is communicated varies wildly. But obedience is a result. Not something you predict. Even if you poll every millisecond a button could be clicked just as the 'initializing' state starts. The important thing isn't to forbid the call. It's to ensure the call can be rejected without causing harm.

If you must ensure multiple states (both not initializing and systemId deleted) you may want to consider a transaction. These can roll back their changes when the requirements fail.

If going that far is really needed depends on how the external system reacts to a delete command while initializing. Does it give an error message or does it enter an invalid state?

If it enters an invalid state it needs fixing. If that's not an option try transactions. But polling it's state to learn when it's OK to delete is just setting you up for a race condition. Best you're doing is lowering the odds that something nasty happens. Not really fixing it. It's the classic mistake of checking if a file exists before writing to it and assuming it still exists between your check and your write. You don't really know.

2
  • 2
    "ensure the call can be rejected without causing harm." and "polling it's state to learn when it's OK to delete is just setting you up for a race condition" are statements that apply to virtually every application I've ever worked on. For some reason, this is a very hard concept to grasp for many people. They tend to think in terms of code rather than disconnected systems interacting with each other, and the fact that more than one client could interact at the same moment. Nobody every thinks this happens until it does. Sep 20, 2022 at 12:21
  • @GregBurghardt the truly nasty problem is you can test the hell out of code that has this bug and never find it. It's like trying to prove a lottery is rigged by playing it. Sep 20, 2022 at 12:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.