On 07/03/2025 08:48, Edmond Dantes wrote:
There is a B2B CRM built on services. Services are classes
instantiated in memory only once via DI, and all that. We process
requests. Requests are executed within a logical *Scope*. The scope
depends on the *TOKEN* and reflects the following entities:
* *User Profile*
* *Company Settings*
We have two implementation options:
1. Pass the user profile and company settings to every method.
2. Use some static variable to make the semantics shorter.
This sounds very much like the same scenario, just different data. The
key requirement is to partition the data based on the request.
Interestingly, like the previous example, the scope is not
per-coroutine, but common to all children of a particular coroutine
spawned by some SAPI / networking layer - it seems that some way to
"label" coroutines/fibers might be useful.
|Async\Context| is designed to *guarantee memory management*, which is
a key aspect for *long-running* applications. It *automatically
releases object references* when a coroutine completes. The programmer
does not need to write *extra code* with |defer()| for this.
That is a good point, and a requirement which I didn't think of.
However, the fact that this didn't stand out in the RFC only reinforces
my key points:
1) Having so many different features in one RFC makes it harder to
discuss their purpose and design than delivering an overall design
first, then adding features.
2) The current Async\Context class doesn't have a clear problem
statement. Even with "guaranteed memory management" as a requirement, we
could have something much simpler.
If such primitives are not included in this or future RFCs, and
instead are left to chance, *it's better not to accept the RFC at all*.
The "or future" in that sentence is key. I'm sorry if I haven't made
this clear enough, but I am *not* saying that none of these features
belong in core; I'm not even saying we need to tag a release without
them. What I'm saying is that they *don't belong in the initial design
document*, at least not in this level of detail.
This is the reason why the current RFC is large. It helps to see the
bigger picture. Once the general principles are agreed upon, we can
split it into parts (Incremental Design).
For me, the opposite is true: the size of the RFC is completely
obscuring the bigger picture, because I "can't see the forest for the
trees", as the saying goes.
I think it's great that you've thought about how these different pieces
will interact, but a lot of them can just be sketches of future scope, e.g.
> It may be useful to have an Async\Context object which can safely
associate arbitrary data with a particular fiber, to use in place of
global/static storage. To do this, we need to track the parent-child
relationship of fibers, and have internal hooks at the start and end of
a fiber's life to allocate and deallocate the storage. An example of
what an Async\Context object implementation might look like is [here],
but the details can be discussed at a later stage.
The fact that the parent-child relationship is valuable is a really
useful thing to know for the overall design. The fact that you don't
like using strings as hashmap keys is not.
As someone not well-versed in the terminology and technology of
concurrency, I find it really hard to see which parts of the RFC are
far-reaching decisions, and which are just bikeshed colours. As a user,
I find it really hard to pick out what PHP code I'll actually write to
make use of this - or even whether I'm the target audience at all, or
whether this is all likely to be hidden by higher-level libraries.
--
Rowan Tommins
[IMSoP]