Embedded, Fast and Persistent bigqueue implementation

PkgGoDev MIT license Build Status codecov

Go Report Card golangci Codacy Badge Maintainability CodeFactor

bigqueue

bigqueue provides embedded, fast and persistent queue written in pure Go using memory mapped (mmap) files. bigqueue is now thread safe as well.

Installation

go get github.com/grandecola/bigqueue

Requirements

  • Only works for linux and darwin OS
  • Only works on Little Endian architecture

Usage

Standard API

Create or open a bigqueue:

bq, err := bigqueue.NewMmapQueue("path/to/queue")
defer bq.Close()

bigqueue persists the data of the queue in multiple Arenas. Each Arena is a file on disk that is mapped into memory (RAM) using mmap syscall. Default size of each Arena is set to 128MB. It is possible to create a bigqueue with custom Arena size:

bq, err := bigqueue.NewMmapQueue("path/to/queue", bigqueue.SetArenaSize(4*1024))
defer bq.Close()

Bigqueue also allows setting up the maximum possible memory that it can use. By default, the maximum memory is set to [3 x Arena Size].

bq, err := bigqueue.NewQueue("path/to/queue", bigqueue.SetArenaSize(4*1024),
	    bigqueue.SetMaxInMemArenas(10))
defer bq.Close()

In this case, bigqueue will never allocate more memory than 4KB*10=40KB. This memory is above and beyond the memory used in buffers for copying data.

Bigqueue allows to set periodic flush based on either elapsed time or number of mutate (enqueue/dequeue) operations. Flush syncs the in memory changes of all memory mapped files with disk. This is a best effort flush.

This is how we can set these options:

bq, err := bigqueue.NewQueue("path/to/queue", bigqueue.SetPeriodicFlushOps(2))

In this case, a flush is done after every two mutate operations.

bq, err := bigqueue.NewQueue("path/to/queue", bigqueue.SetPeriodicFlushDuration(time.Minute))

In this case, a flush is done after one minute elapses and an Enqueue/Dequeue is called.

Write to bigqueue:

err := bq.Enqueue([]byte("elem"))

bigqueue allows writing string data directly, avoiding conversion to []byte:

err := bq.EnqueueString("elem")

Read from bigqueue:

elem, err := bq.Dequeue()

we can also read string data from bigqueue:

elem, err := bq.DequeueString()

Check whether bigqueue has non zero elements:

isEmpty := bq.IsEmpty()

Advanced API

bigqueue allows reading data from bigqueue using consumers similar to Kafka. This allows multiple consumers from reading data at different offsets (not in thread safe manner yet). The offsets of each consumer are persisted on disk and can be retrieved by creating a consumer with the same name. Data will be read from the same offset where it was left off.

We can create a new consumer as follows. The offsets of a new consumer are set at the start of the queue wherever the first non-deleted element is.

consumer, err := bq.NewConsumer("consumer")

We can also copy an existing consumer. This will create a consumer that will have the same offsets into the queue as that of the existing consumer.

copyConsumer, err := bq.FromConsumer("copyConsumer", consumer)

Now, read operations can be performed on the consumer:

isEmpty := consumer.IsEmpty()
elem, err := consumer.Dequeue()
elem, err := consumer.DequeueString()

Benchmarks

Benchmarks are run on a Lenovo P52s laptop (i7-8550U, 8 core @1.80GHz, 15.4GB RAM) having ubuntu 18.10, 64 bit machine.

Go version: 1.13

NewMmapQueue

BenchmarkNewMmapQueue/ArenaSize-4KB-8         	     279	   4206291 ns/op	    2401 B/op	      38 allocs/op
BenchmarkNewMmapQueue/ArenaSize-128KB-8       	     285	   4218564 ns/op	    2400 B/op	      38 allocs/op
BenchmarkNewMmapQueue/ArenaSize-4MB-8         	     288	   4251324 ns/op	    2401 B/op	      38 allocs/op
BenchmarkNewMmapQueue/ArenaSize-128MB-8       	     288	   4169841 ns/op	    2400 B/op	      38 allocs/op

Enqueue

BenchmarkEnqueue/ArenaSize-4KB/MessageSize-128B/MaxMem-12KB-8         	 1277236	       935 ns/op	      48 B/op	       1 allocs/op
BenchmarkEnqueue/ArenaSize-4KB/MessageSize-128B/MaxMem-40KB-8         	 1268900	       968 ns/op	      48 B/op	       1 allocs/op
BenchmarkEnqueue/ArenaSize-4KB/MessageSize-128B/MaxMem-NoLimit-8      	 1412449	       851 ns/op	      48 B/op	       1 allocs/op
BenchmarkEnqueue/ArenaSize-128KB/MessageSize-4KB/MaxMem-384KB-8       	  336560	      3584 ns/op	      47 B/op	       1 allocs/op
BenchmarkEnqueue/ArenaSize-128KB/MessageSize-4KB/MaxMem-1.25MB-8      	  335191	      3926 ns/op	      47 B/op	       1 allocs/op
BenchmarkEnqueue/ArenaSize-128KB/MessageSize-4KB/MaxMem-NoLimit-8     	  305390	      3354 ns/op	      47 B/op	       1 allocs/op
BenchmarkEnqueue/ArenaSize-4MB/MessageSize-128KB/MaxMem-12MB-8        	   13652	     86532 ns/op	      46 B/op	       1 allocs/op
BenchmarkEnqueue/ArenaSize-4MB/MessageSize-128KB/MaxMem-40MB-8        	   13773	     84258 ns/op	      46 B/op	       1 allocs/op
BenchmarkEnqueue/ArenaSize-4MB/MessageSize-128KB/MaxMem-NoLimit-8     	   13807	     89458 ns/op	      46 B/op	       1 allocs/op
BenchmarkEnqueue/ArenaSize-128MB/MessageSize-4MB/MaxMem-256MB-8       	     448	   2910430 ns/op	      46 B/op	       1 allocs/op
BenchmarkEnqueue/ArenaSize-128MB/MessageSize-4MB/MaxMem-1.25GB-8      	     442	   3123539 ns/op	      45 B/op	       1 allocs/op
BenchmarkEnqueue/ArenaSize-128MB/MessageSize-4MB/MaxMem-NoLimit-8     	     453	   3016637 ns/op	      46 B/op	       1 allocs/op

EnqueueString

BenchmarkEnqueueString/ArenaSize-4KB/MessageSize-128B/MaxMem-12KB-8   	 1274005	       963 ns/op	      32 B/op	       1 allocs/op
BenchmarkEnqueueString/ArenaSize-4KB/MessageSize-128B/MaxMem-40KB-8   	 1244082	       982 ns/op	      32 B/op	       1 allocs/op
BenchmarkEnqueueString/ArenaSize-4KB/MessageSize-128B/MaxMem-NoLimit-8         	 1432782	       887 ns/op	      32 B/op	       1 allocs/op
BenchmarkEnqueueString/ArenaSize-128KB/MessageSize-4KB/MaxMem-384KB-8          	  300306	      3668 ns/op	      31 B/op	       1 allocs/op
BenchmarkEnqueueString/ArenaSize-128KB/MessageSize-4KB/MaxMem-1.25MB-8         	  336058	      3684 ns/op	      31 B/op	       1 allocs/op
BenchmarkEnqueueString/ArenaSize-128KB/MessageSize-4KB/MaxMem-NoLimit-8        	  365847	      3534 ns/op	      31 B/op	       1 allocs/op
BenchmarkEnqueueString/ArenaSize-4MB/MessageSize-128KB/MaxMem-12MB-8           	   13741	     86820 ns/op	      30 B/op	       1 allocs/op
BenchmarkEnqueueString/ArenaSize-4MB/MessageSize-128KB/MaxMem-40MB-8           	   13714	     86950 ns/op	      30 B/op	       1 allocs/op
BenchmarkEnqueueString/ArenaSize-4MB/MessageSize-128KB/MaxMem-NoLimit-8        	   13804	     93003 ns/op	      30 B/op	       1 allocs/op
BenchmarkEnqueueString/ArenaSize-128MB/MessageSize-4MB/MaxMem-256MB-8          	     417	   2893948 ns/op	      30 B/op	       1 allocs/op
BenchmarkEnqueueString/ArenaSize-128MB/MessageSize-4MB/MaxMem-1.25GB-8         	     444	   3127065 ns/op	      29 B/op	       1 allocs/op
BenchmarkEnqueueString/ArenaSize-128MB/MessageSize-4MB/MaxMem-NoLimit-8        	     429	   2910933 ns/op	      30 B/op	       1 allocs/op

Dequeue

BenchmarkDequeue/ArenaSize-4KB/MessageSize-128B/MaxMem-12KB-8                  	 1000000	      2901 ns/op	     175 B/op	       2 allocs/op
BenchmarkDequeue/ArenaSize-4KB/MessageSize-128B/MaxMem-40KB-8                  	 1000000	      2921 ns/op	     175 B/op	       2 allocs/op
BenchmarkDequeue/ArenaSize-4KB/MessageSize-128B/MaxMem-NoLimit-8               	 5159112	       246 ns/op	     160 B/op	       2 allocs/op
BenchmarkDequeue/ArenaSize-128KB/MessageSize-4KB/MaxMem-384KB-8                	  488948	      3235 ns/op	    4142 B/op	       2 allocs/op
BenchmarkDequeue/ArenaSize-128KB/MessageSize-4KB/MaxMem-1.25MB-8               	  524533	      3275 ns/op	    4142 B/op	       2 allocs/op
BenchmarkDequeue/ArenaSize-128KB/MessageSize-4KB/MaxMem-NoLimit-8              	  851850	      1408 ns/op	    4128 B/op	       2 allocs/op
BenchmarkDequeue/ArenaSize-4MB/MessageSize-128KB/MaxMem-12MB-8                 	   25760	     45141 ns/op	  131118 B/op	       2 allocs/op
BenchmarkDequeue/ArenaSize-4MB/MessageSize-128KB/MaxMem-40MB-8                 	   26340	     44453 ns/op	  131118 B/op	       2 allocs/op
BenchmarkDequeue/ArenaSize-4MB/MessageSize-128KB/MaxMem-NoLimit-8              	   36206	     40891 ns/op	  131104 B/op	       2 allocs/op
BenchmarkDequeue/ArenaSize-128MB/MessageSize-4MB/MaxMem-256MB-8                	     633	   2284370 ns/op	 4194349 B/op	       2 allocs/op
BenchmarkDequeue/ArenaSize-128MB/MessageSize-4MB/MaxMem-1.25GB-8               	     775	   1845506 ns/op	 4194345 B/op	       2 allocs/op
BenchmarkDequeue/ArenaSize-128MB/MessageSize-4MB/MaxMem-NoLimit-8              	     808	   1930464 ns/op	 4194336 B/op	       2 allocs/op

DequeueString

BenchmarkDequeueString/ArenaSize-4KB/MessageSize-128B/MaxMem-12KB-8            	 1000000	      3065 ns/op	     183 B/op	       3 allocs/op
BenchmarkDequeueString/ArenaSize-4KB/MessageSize-128B/MaxMem-40KB-8            	 1000000	      3045 ns/op	     183 B/op	       3 allocs/op
BenchmarkDequeueString/ArenaSize-4KB/MessageSize-128B/MaxMem-NoLimit-8         	 4386606	       287 ns/op	     168 B/op	       3 allocs/op
BenchmarkDequeueString/ArenaSize-128KB/MessageSize-4KB/MaxMem-384KB-8          	  506248	      3375 ns/op	    4150 B/op	       3 allocs/op
BenchmarkDequeueString/ArenaSize-128KB/MessageSize-4KB/MaxMem-1.25MB-8         	  502797	      3352 ns/op	    4150 B/op	       3 allocs/op
BenchmarkDequeueString/ArenaSize-128KB/MessageSize-4KB/MaxMem-NoLimit-8        	  826635	      1391 ns/op	    4136 B/op	       3 allocs/op
BenchmarkDequeueString/ArenaSize-4MB/MessageSize-128KB/MaxMem-12MB-8           	   25773	     45963 ns/op	  131126 B/op	       3 allocs/op
BenchmarkDequeueString/ArenaSize-4MB/MessageSize-128KB/MaxMem-40MB-8           	   26059	     46397 ns/op	  131126 B/op	       3 allocs/op
BenchmarkDequeueString/ArenaSize-4MB/MessageSize-128KB/MaxMem-NoLimit-8        	   35088	     41857 ns/op	  131112 B/op	       3 allocs/op
BenchmarkDequeueString/ArenaSize-128MB/MessageSize-4MB/MaxMem-256MB-8          	     655	   1995248 ns/op	 4194357 B/op	       3 allocs/op
BenchmarkDequeueString/ArenaSize-128MB/MessageSize-4MB/MaxMem-1.25GB-8         	     786	   1864277 ns/op	 4194353 B/op	       3 allocs/op
BenchmarkDequeueString/ArenaSize-128MB/MessageSize-4MB/MaxMem-NoLimit-8        	     668	   1973988 ns/op	 4194344 B/op	       3 allocs/op

Note: Before running benchmarks ulimit and vm.max_map_count parameters should be adjusted using below commands:

ulimit -n 50000
echo 262144 > /proc/sys/vm/max_map_count
Comments
  • Flush arenas upon N mutate operations or time elapsed since last flush

    Flush arenas upon N mutate operations or time elapsed since last flush

    Fixes #41

    Allow to make durability vs performance choices by choosing explicit flush intervals in two ways:

    • Flush when number of mutate operations (enqueue/dequeue) has become more than a threshold
    • Elapsed time since previous flush has become more than a certain duration
  • Refactored and added dequeueAppend

    Refactored and added dequeueAppend

    DequeueAppend allows to dequeue data without allocations at all by reusing byte slice Increased speed of Dequeue/Enqueue methods by omitting interfaces usage, some code duplications possible, but it's a Golang before generics)

  • Allow flushing periodically

    Allow flushing periodically

    We should expose the flush function as part of the bigqueue interface. Additionally, we should not trust the OS periodic syncing, and instead, enable flushing periodically, with a timer or probably by amount of data change, with configuration parameters to choose the period.

  • Provide functions to read/write string directly to Arena

    Provide functions to read/write string directly to Arena

    Currently, we need to first copy the string (say) into an array of bytes. Then, we will copy this array into the Arena. The double copy can be avoided.

  • Reduce enqueue and dequeue allocations

    Reduce enqueue and dequeue allocations

    @mangalaman93, @ashish-goswami please take a look! You will be happy with benchmark) only 1 allocation to dequeue, both dequeueString and dequeue and no allocations to enqueue. Before:

    cpu: Intel(R) Core(TM) i5-7600 CPU @ 3.50GHz
    BenchmarkEnqueue
    BenchmarkEnqueue/ArenaSize-4KB/MessageSize-128B/MaxMem-12KB
    BenchmarkEnqueue/ArenaSize-4KB/MessageSize-128B/MaxMem-12KB-4         	  225560	      6584 ns/op	      45 B/op	       1 allocs/op
    BenchmarkEnqueue/ArenaSize-4KB/MessageSize-128B/MaxMem-40KB
    BenchmarkEnqueue/ArenaSize-4KB/MessageSize-128B/MaxMem-40KB-4         	  351213	      5216 ns/op	      45 B/op	       1 allocs/op
    

    After:

    cpu: Intel(R) Core(TM) i5-7600 CPU @ 3.50GHz
    BenchmarkEnqueue
    BenchmarkEnqueue/ArenaSize-4KB/MessageSize-128B/MaxMem-12KB
    BenchmarkEnqueue/ArenaSize-4KB/MessageSize-128B/MaxMem-12KB-4         	  325824	      3537 ns/op	      18 B/op	       0 allocs/op
    BenchmarkEnqueue/ArenaSize-4KB/MessageSize-128B/MaxMem-40KB
    BenchmarkEnqueue/ArenaSize-4KB/MessageSize-128B/MaxMem-40KB-4         	  320850	      3857 ns/op	      18 B/op	       0 allocs/op
    

    Looking forward to your feedback

  • Reduce arenamanager allocations

    Reduce arenamanager allocations

    Reduce memory allocation with same path behaiviour, clean dir once instead of doing it each time.

    As an alternative we can do

    var b strings.Builder
    a := strconv.Itoa(i)
    b.Grow(len(dir) + 1 + len(a) + len(cArenaFilePrefix))
    b.WriteString(dir)
    b.WriteByte('/')
    b.WriteString(a)
    b.WriteString(cArenaFilePrefix)
    

    but it's slightly slower

    
    func BenchmarkSpeeds(b *testing.B) {
    	b.Run("compare speeds", func(b *testing.B) {
    		var dir = "/home/user/datadir"
    		var p = ""
    		b.Run("builder", func(b *testing.B) {
    			b.ReportAllocs()
    			for i := 0; i < b.N; i++ {
    				var b strings.Builder
                                    a := strconv.Itoa(i)
    				b.Grow(len(dir) + 1 + len(a) + len("_arena.dat"))
    				b.WriteString(dir)
    				b.WriteByte('/')
    				b.WriteString(a)
    				b.WriteString("_arena.dat")
    				p = b.String()
    			}
    		})
    		b.Run("slice", func(b *testing.B) {
    			var filePath []byte
    			b.ReportAllocs()
    			for i := 0; i < b.N; i++ {
    				filePath = append(filePath[:0], dir...)
    				filePath = append(filePath, '/')
    				filePath = strconv.AppendInt(filePath, int64(i), 10)
    				filePath = append(filePath, "_arena.dat"...)
    				p = string(filePath)
    			}
    		})
    		b.Run("path", func(b *testing.B) {
    			b.ReportAllocs()
    			for i := 0; i < b.N; i++ {
    				fileName := strconv.Itoa(i) + "_arena.dat"
    				p = path.Join(dir, fileName)
    			}
    		})
    		runtime.KeepAlive(p)
    	})
    }
    
    
    cpu: Intel(R) Core(TM) i5-7600 CPU @ 3.50GHz
    BenchmarkSpeeds
    BenchmarkSpeeds/compare_speeds
    BenchmarkSpeeds/compare_speeds/builder
    BenchmarkSpeeds/compare_speeds/builder-4 	15500703	        76.11 ns/op	      55 B/op	       1 allocs/op
    BenchmarkSpeeds/compare_speeds/slice
    BenchmarkSpeeds/compare_speeds/slice-4   	23539419	        56.07 ns/op	      47 B/op	       1 allocs/op
    BenchmarkSpeeds/compare_speeds/path
    BenchmarkSpeeds/compare_speeds/path-4    	 5428278	       203.3 ns/op	     103 B/op	       2 allocs/op
    

    @mangalaman93, @ashish-goswami please take a look!

  • Update APIs to use offsets

    Update APIs to use offsets

    This is along the lines of how Kafka works. Given that bigqueue is persistent, it makes a lot of sense to not delete the data after it is read once. Certainly, it could be configured to do so, but that shouldn't be the default choice. Instead, we should allow using offsets per client so that the data could be read from anywhere in the queue as needed.

  • Add support for configuring bigqueue

    Add support for configuring bigqueue

    We should use a Config object to allow configuring BigQueue. We should allow a useful default value for each configuration as well as ensure that configurations are set correctly using possible checks around each parameter. We should allow creating bigqueue without the config object using the default values.

    Here is the list of configuration parameters -

    • [ ] Maximum size of Arena (check for a value at least as much as size of a OS page)
    • [ ] Maximum memory used by BigQueue, allow an option for using minimum possible memory, or all available memory (check for a value of at least as much as 2 * Size of Arena)
    • [ ] GC frequency (check for a positive value)

    We will have to persist the configuration parameters so that we can read these parameters back across different invocation of same application.

    I still think that we should keep the directory as an argument to NewBigQueue to ensure an explicit invocation of creating a queue using a path. Given that path is what defines a BigQueue, the expectation will be set properly in that if you lose the directory, you lose the queue

  • Add support for writing String data into bigqueue

    Add support for writing String data into bigqueue

    Fixes #19

    benchmarks

    $ go test -bench=BenchmarkStringDoubleCopy
    goos: linux
    goarch: amd64
    pkg: github.com/grandecola/bigqueue
    BenchmarkStringDoubleCopy-8   	10000000	       151 ns/op
    PASS
    ok  	github.com/grandecola/bigqueue	8.464s
    
    $ go test -bench=BenchmarkStringNoCopy
    goos: linux
    goarch: amd64
    pkg: github.com/grandecola/bigqueue
    BenchmarkStringNoCopy-8   	10000000	       112 ns/op
    PASS
    ok  	github.com/grandecola/bigqueue	7.8788
    
  • Why mmap?

    Why mmap?

    Just curious, why mmap the files? It seems like simply writing serially and reading serially also should work, no? Would also give higher control over flushing and buffering.

  • Add support for multithreading

    Add support for multithreading

    We can try two difference approaches -

    • In this approach, we keep the queue single threaded and acquire lock from outside
    • In this approach, we acquire locks on all the subcomponents such as index, arena.
  • Limit memory size not available

    Limit memory size not available

    Bigqueue. Setarenasize() default 128M

    Bigqueue. Setmaxinmememarenas() defaults to 3

    Theoretically, the maximum number of Enqueue data is 128 * 3, but in practice, I can test unlimited Enqueue data.

    How can I limit the Enqueue data to 1024m?

  • Concurrent requests/reply IPC

    Concurrent requests/reply IPC

    I'm trying to improve the throughput of an app I'm building. Essentially, it currently uses Unix Domain Sockets to transfer messages between two processes. This is because they are well supported in many programming languages, and easy to use for request/reply.

    But combining the two process into a single process I get 10x the TPS. So I know there is up-to 10x potential improvement.

    My questions is, can mmap do this, give some constraints:

    • Request/reply (like HTTP).
    • Concurrent, multiple request/replies in flight.
  • Write multicore benchmark and Improve performance

    Write multicore benchmark and Improve performance

    Benchmarks currently single threaded. Now that bigqueue is thread safe, we should be able to utilize the multi core performance for a higher throughput. We can also profile the system and improve the performance.

A simple persistent directory-backed FIFO queue.

pqueue pqueue is a simple persistent directory-backed FIFO queue. It provides the typical queue interface Enqueue and Dequeue and may store any byte s

Dec 12, 2022
Persistent queue in Go based on BBolt

Persistent queue Persistent queue based on bbolt DB. Supposed to be used as embeddable persistent queue to any Go application. Features: messages are

Jun 30, 2022
ChizBroker is a fast and simple GRPC based implementation of kafka.
ChizBroker is a fast and simple GRPC based implementation of kafka.

Chiz Broker: a broker for fun ChizBroker is a fast and simple GRPC based implementation of kafka. Features: Ready to be deployed on kubernetes Prometh

Oct 30, 2022
Inspr is an application mesh for simple, fast and secure development of distributed applications.
Inspr is an application mesh for simple, fast and secure development of distributed applications.

Inspr is an engine for running distributed applications, using multiple communication patterns such as pub sub and more, focused on type consistency a

Jun 10, 2022
🔥 A fast and beautiful command line tool to build API requests.
🔥 A fast and beautiful command line tool to build API requests.

Poodle A fast and beautiful command line tool to build API requests ?? Check out the full Demo! Poodle is an interactive command line tool to build an

Aug 23, 2022
Imagine a simple, beautiful, secure, and freaking fast way to broadcast your events throw the internet

Event Superintendent Imagine a simple, beautiful, secure, and freaking fast way to broadcast your events throw the internet. That's exactly why you sh

Jul 18, 2022
:incoming_envelope: A fast Message/Event Hub using publish/subscribe pattern with support for topics like* rabbitMQ exchanges for Go applications

Hub ?? A fast enough Event Hub for go applications using publish/subscribe with support patterns on topics like rabbitMQ exchanges. Table of Contents

Dec 17, 2022
A fast durable queue for Go

pqueue - a fast durable queue for Go pqueue is thread-safety, serves environments where more durability is required (e.g., outages last longer than me

Oct 16, 2022
Server-sent live updates: protocol and reference implementation
Server-sent live updates: protocol and reference implementation

Protocol and Reference Implementation Mercure is a protocol allowing to push data updates to web browsers and other HTTP clients in a convenient, fast

Jan 1, 2023
Implementation of the NELI leader election protocol for Go and Kafka
Implementation of the NELI leader election protocol for Go and Kafka

goNELI Implementation of the NELI leader election protocol for Go and Kafka. goNELI encapsulates the 'fast' variation of the protocol, running in excl

Dec 8, 2022
graylog-golang is a full implementation for sending messages in GELF (Graylog Extended Log Format) from Go (Golang) to Graylog

graylog-golang is a full implementation for sending messages in GELF (Graylog Extended Log Format) from Go (Golang) to Graylog

Dec 5, 2022
🔊Minimalist message bus implementation for internal communication

?? Bus Bus is a minimalist event/message bus implementation for internal communication. It is heavily inspired from my event_bus package for Elixir la

Jan 3, 2023
The implementation of the pattern observer

Event This is package implements pattern-observer Fast example import ( "github.com/agoalofalife/event" ) func main() { // create struct e := even

Dec 4, 2022
Package notify provides an implementation of the Gnome DBus Notifications Specification.

go-notify Package notify provides an implementation of the Gnome DBus Notifications Specification. Examples Display a simple notification. ntf := noti

Dec 27, 2022
mangos is a pure Golang implementation of nanomsg's "Scalablilty Protocols"
mangos is a pure Golang implementation of nanomsg's

mangos Mangos™ is an implementation in pure Go of the SP (“Scalability Protocols”) messaging system. These are colloquially known as a “nanomsg”. ❗ Th

Jan 1, 2023
POC of an event-driven Go implementation

Event Driven example in Golang This POC shows an example of event-driven architecture with a working domain event broker, an event producer and a cons

Nov 2, 2021
⚡️ A lightweight service that will build and store your go projects binaries, Integrated with Github, Gitlab, Bitbucket and Bitbucket Server.
⚡️ A lightweight service that will build and store your go projects binaries, Integrated with Github, Gitlab, Bitbucket and  Bitbucket Server.

Rabbit A lightweight service that will build and store your go projects binaries. Rabbit is a lightweight service that will build and store your go pr

Nov 19, 2022
Cadence is a distributed, scalable, durable, and highly available orchestration engine to execute asynchronous long-running business logic in a scalable and resilient way.

Cadence Visit cadenceworkflow.io to learn about Cadence. This repo contains the source code of the Cadence server. To implement workflows, activities

Jan 9, 2023
The Xiaomi message push service is a system-level channel on MIUI and is universal across the platform, which can provide developers with stable, reliable, and efficient push services.

Go-Push-API MiPush、JiPush、UMeng MiPush The Xiaomi message push service is a system-level channel on MIUI and is universal across the platform, which c

Oct 20, 2022