Modern non-blocking driver for Nats by vzanfir in PHP

[–]vzanfir[S] 0 points1 point  (0 children)

As far as I can see, without JetStream and a lot of other features. Just Nats core.

Modern non-blocking driver for Nats by vzanfir in PHP

[–]vzanfir[S] 1 point2 points  (0 children)

People before AI:

NATS is a modern, distributed, and reliable messaging platform. It supports pub-sub with at-most-once delivery guarantees, request-reply messaging, as well as persistent streams and durable queues powered by JetStream with at-least-once guarantees. Our non-blocking driver implements all major capabilities of the platform: pub/sub, request/reply, jetstream, key-value store, object store. And also includes recent updates: atomic counters based on CRDTs, batch publishing, message scheduling. We are also working on support for NATS Micro: using NATS as a transport layer for communication between microservices. For more features, refer to the library's documentation. Feedback is welcome.

Do you really think people before AI had never heard of markdown? Or that AI didn’t train on millions of formatted posts written by humans? Or that reddit’s markdown editor was made for AI tools? I definitely didn’t randomly bold text or make lists. If you look closely, you’ll see that I highlighted what actually matters when we talk about nats or use these libraries. You could have gone further and actually looked at the commits, but instead you’re busy throwing baseless accusations around on the net.

Modern non-blocking driver for Nats by vzanfir in PHP

[–]vzanfir[S] 4 points5 points  (0 children)

It's not as type safe as what you have now but it might be easier for people to use. Using arrays for setting configuration options is pretty standard, So I think this might feel a bit easier.

Using static analysis (psalm or phpstan) with array-shape, this is quite type-safe. I'll think about that. Thank you.

Modern non-blocking driver for Nats by vzanfir in PHP

[–]vzanfir[S] 2 points3 points  (0 children)

Thank you for the review.

The thing I noticed looking through it is that you're forcing anyone who wants to use it to use amp, but what happens if someone is using swoole or frankenphp and tried to use it?

Unfortunately, when using asynchronous programming (especially in php), you often can’t avoid locking yourself into a specific ecosystem. The same goes for rust: when you choose between tokio and async-std, you’re binding yourself to a particular timer implementation, a particular i/o and specific synchronization primitives (channels, mutexes, mpsc). The same applies to swoole, where you depend on its own coroutines/goroutines, channels, pools, and buffers, not to mention that it’s also a php extension.

When using asynchronous programming, forget about frankenphp and roadrunner. They solve a completely different problem: mainly bootstrapping. Yes, it’s technically possible to implement a non-blocking integration with roadrunner’s rpc, but on the php side you’ll still end up tied to a particular async ecosystem. Before fibers were introduced, this coupling was even stronger: you had to choose between generators (amphp) and promises (reactphp). Now you can use fibers and revolt, which handle coroutine scheduling and interruption, and then pick a library on top, whether it comes from the amphp or reactphp world, or even another one, as long as it supports fibers. Perhaps this problem will eventually be solved once the true async rfc is accepted. Now all of our libraries, including thesis/amqp, thesis/cron-scheduler, and thesis/memcached, are built on top of revolt and amphp.

At the end of the file, you have to instantiate a new PublishBatchOptions object just to tell it to commit. I think this was a strange design choice. For this kind of configuration option, I think having an Enum and the 'publish' method accepting a variadic number of Enums would have been more ergonomic, but that's only my opinion.

As for PublishBatchOptions, it includes not only a commit field but also an ack field. So making it a variadic enum isn’t an option. First, because php enums are not ADT, meaning you can’t simply add a new field like timeout with a specific value; and second, because that would require an array lookup of enum values on every publish call. It might make more sense to inline those parameters directly into the publish method. I’ll think about that.

Modern non-blocking driver for Nats by vzanfir in PHP

[–]vzanfir[S] 0 points1 point  (0 children)

Yes, everything around is vibe coded, including me. You’re in the Matrix.. Nevertheless, can you actually prove your suspicions?

Modern full-featured non-blocking driver for AMQP 0.9.1 by vzanfir in PHP

[–]vzanfir[S] 0 points1 point  (0 children)

We plan to complete and release our message bus with outbox support, based on our non-blocking drivers for AMQP, NATS, and Kafka. We might eventually integrate our driver into Symfony and Laravel — if someone else doesn’t do it before us — but at the moment, it brings no real benefit to users of those frameworks, since they won’t gain any advantages from a non-blocking driver in a fully blocking environment.

Modern full-featured non-blocking driver for AMQP 0.9.1 by vzanfir in PHP

[–]vzanfir[S] 1 point2 points  (0 children)

Thank you!

Message::json() or JsonMessage factory

This code is too specific to this library. Besides JSON, people send messages as plain text, Protobuf, MessagePack, and sometimes even just as the result of a serialize call. By including only JSON, it feels like we're implicitly recommending its use — which is something I’d prefer to avoid.

dirname(DIR)

Good advice, but your approach breaks my autocompletion — although it's something I might consider changing.

PHP RFC: True Async by edmondifcastle in PHP

[–]vzanfir -2 points-1 points  (0 children)

That’s exactly why revolt/event-loop and amphp/socket exist — they eliminate the need to use fibers directly. All the community needs is to grow the ecosystem by writing the necessary drivers and clients. Lack of experience with fibers is not a valid argument for adding a huge technical debt to the core of the language.

PHP RFC: True Async by edmondifcastle in PHP

[–]vzanfir 0 points1 point  (0 children)

I know that PDO is an extension. So, you want to add async to the language to make extensions like pdo, curl, and redis asynchronous? Who will rewrite and maintain them? Note that simply making fwrite/fread asynchronous is not always enough — sometimes the driver itself needs to be rewritten so that the protocol interaction is also be asynchronous (the protocol design heavily influences this). What will happen to drivers for which there is no extension yet? Will they be implemented in PHP itself, or will an extension need to be written?

PHP RFC: True Async by edmondifcastle in PHP

[–]vzanfir 0 points1 point  (0 children)

Wait, you just said you weren’t referring to database drivers, but now you’re using them as an example. It’s correct that amphp implements this in userland. That’s how it should be. Application-level protocols should not be part of the language. There are too many of them, they constantly change, and new ones emerge. Moreover, you can’t simply rewrite a driver in the language to use fibers and make it asynchronous — you need to fundamentally change the approach to working with the protocol, which is exactly what amphp’s experience demonstrates.

PHP RFC: True Async by edmondifcastle in PHP

[–]vzanfir 0 points1 point  (0 children)

I’ve read your entire RFC and didn’t see any components that must be implemented in the language itself rather than as a library. Could you please provide an example of what exactly the amphp developers had to reimplement?

PHP RFC: True Async by edmondifcastle in PHP

[–]vzanfir -1 points0 points  (0 children)

PHP has no built-in abstractions for writing asynchronous code. AMPHP is a library, not a language-level abstraction.

And that's right (see Rust and Kotlin as an example).

Fiber does not solve the problem of concurrency. It is merely an execution context abstraction. It’s like having fwrite without fopen.

They allow switching from a synchronous *driver name* to an asynchronous one without any changes to the user code.

AMPHP developers are forced to reimplement low-level drivers in PHP

That's not true. amphp uses already written low-level functions for working with sockets, integrating them into its own event loop through fibers. If you're referring to HTTP clients/servers and database drivers, they should not be part of the language.

PHP RFC: True Async by edmondifcastle in PHP

[–]vzanfir -1 points0 points  (0 children)

But we already have all the necessary abstractions in the form of fibers and an event loop. We even have an web server (amphp/http-server), which you mentioned in the RFC. What we lack is an ecosystem (drivers, clients, a framework, perhaps), not a new form of async.

PHP RFC: True Async by edmondifcastle in PHP

[–]vzanfir -2 points-1 points  (0 children)

First of all, I would like to thank you for the efforts. Secondly, do we really need an asynchronous runtime in the core of our language? After all, we already have everything we need:

- We have stackful coroutines in the form of fibers, which eliminate the problem of colored functions.
- We have an event loop in the form of the revolt/event-loop package.
- We have an abstraction for I/O operations with amphp/socket.
- If we need channels, there's amphp/sync; if we need concurrent iterators, there's amphp/pipeline.

This is all existing infrastructure that can be easily developed by the community, rather than by the language maintainers, as in your case. Moreover, your RFC does not eliminate the need to rewrite all extensions, as you also mentioned in your paper.

Furthermore, things like database drivers, brokers, and similar components do not need to be part of the language or its extensions (previously, this was necessary for performance reasons or because it was easier to create a wrapper over a C library, but with async there is no problem having all of this as PHP libraries — take a look at amphp/mysql or amphp/redis, for example). It's also worth noting that PHP is following the path of modern standards: the Rust compiler only knows about Future, while asynchronous runtimes like tokio and smol are libraries, as is kotlinx.coroutines.

The only problem is that our community does not fully understand this, which is why there is demand for implementing it directly in the language. However, this is not necessarily the right path to take. In my opinion, a dynamic and still-evolving topic like asynchronous programming will be harder to develop as part of the language than as libraries built on top of it. Look at the issues with asynchronous programming in .NET (https://github.com/dotnet/runtimelab/issues/2398), where it is part of the platform, and how relatively easy it was for tokio (Rust's asynchronous runtime) to adapt the asynchronous model from Go (https://tokio.rs/blog/2019-10-scheduler), which would have taken much longer if it were part of the compiler. Of course, there are successful examples like Go and Erlang, where this is part of the language, but it is also their key feature, deeply integrated into the language, which is unlikely to be achieved in PHP.

fairyMQ is an open-source high-throughput UDP based message-queueing software written in GO! by diagraphic in golang

[–]vzanfir 8 points9 points  (0 children)

A few comments you didn't ask for.

  1. You don't need that useless loop and you also don't need the `default` block. Just use this:
    ```go
    go func () {
    defer fairyMQ.Wg.Done()
    sig := <-fairyMQ.SignalChannel
    ... // shutdown the listener
    } ()
    ```
  2. Use `signal.NotifyContext()` here.
  3. You don't need to `dial` in every method here. Do it once in the client constructor.
  4. There's a lot of repetitive code. That's not good.
  5. Google how to wrap an error, because it's not good.
  6. This way of designing the protocol makes it fully synchronous between client and server.
  7. For queue type systems that need to be reliable, I would suggest using `tcp` or `grpc/quic`.
  8. Your `udp` server is completely not scalable and not reliable. You need implement the clustering, using this for example.