Implementation of progressive Publish-Subscribe scenarios in Pony, as a means to document an adaptation to the Actor Model paradigm and the problems it may solve.
The main goals of this project were:
- Infer patterns on how to design Publish/Subscribe systems on an Actor Model language;
- Assess how differently (if at all) traditional OOP design patterns still apply on Pony's paradigm;
- Evaluate Pony's core features (capabilities-secure, actor-model) help/hinger on solving the Publish/Subscribe problem;
- Evaluate Pony as a production-level programming language, from various perspectives, e.g., learning curve, community, documentation, stability, etc;
- Unbounded queue;
- Publisher sends messages a.s.a.p.;
- Subscriber tries to pull messages and blocks (
awaits
) until it has one; - Implicit subscription (fetch directly from data structure).
- Unbounded queue and publishes asap (again);
- Multiple subscribers:
- They pull messages concurrently;
- Each gets a different message;
- Implicit subscription (fetch from data structure).
- Unbounded queue and publishes asap (again);
- Ventilator (or Subscription Manager) knows about the subscribers:
- Multiple publishers, multiple subscribers;
- Both have specialized queues:
- Inbound and Outbound;
- Broker manages queue binding;
- Broker moves messages around (between queues);
- Queues may be persistent;
- No implicit connections between subscribers and producers:
- Explicit subscription;
- Identification mechanism is needed (keys, topics, ...);
- Study the Registry and (if you are feeling adventurous) the Service Locator patterns.
- Remove the notion of queue altogether;
- Instead, make use of Pony's messaging system, namely through Actor behaviours;
The end product of a Publish/Subscribe system on an Actor Model language proved to be somewhat similar to traditional OOP implementations. However, we find that to be misleading, as it doesn't reflect the learning curve associated with the language's features, i.e., reference capabilities.
The major difference in terms of data structures was the lack of need of an explicit queue since Pony's implementation of the Actor Model's mailboxes abstracts them through behaviors (similar to class methods, but asynchronous).
Pony handles the threads for its Actors, meaning you don't have to deal with its creation, destruction or even data-races and deadlocks. Additionally, the code is inherently asynchronous, if you follow the language's functionalities as intended. This is an advantage when comparing to languages such as C++, where the parallelism is explicit, namely through dedicated parallel operations, suchs as fork calls.
Naturally, multi-threading is an advantage against single-threaded asynchronous event-loop-based programming languages, such as the Node.js environment, both in terms of performance and parallelism abstractions.
Pony is still a relatively new language and therefore it was expected to encounter some problems with stability, documentation and community. However, we found no stability issues or unexpected behaviour. The documentation is well written and fairly easy to search. Community wise, it lacks support from questions websites like StackOverflow (with only 56 watchers and 25 questions for the language tag, comparing to 10.3k/12.4k from Rust).
However, Pony does have good support on Zulip, where you can also ask questions and contribute to the community. Pony is also open-source, allowing the community to point out issues and fix/implement functionality. From a learning perspective, Pony introduces a clean syntax, easy library usage and simple compilation/linking instructions. However, some of its peculiarities, such as its Reference Capabilities can make up a steep learning curve.
Pony is not only a typed language, which enables more maintainable code, but also type-safe (and, therefore, memory-safe). It also guarantees exception safety, meaning if the program compiles it will run with no unexpected exceptions. All of these capabilities helped to develop safer and cleaner code.
Install pony compiler ponyc
# compile the package
$ make build/asso
# compile tests
$ make build/test
Note: both these commands will build the source code to a specific directory.
# run the package's Main, build to /asso
$ make run
# run tests, build to /test
$ make test