{"id":37127445,"url":"https://github.com/egemengol/spread","last_synced_at":"2026-01-14T14:50:31.261Z","repository":{"id":224397629,"uuid":"763156451","full_name":"egemengol/spread","owner":"egemengol","description":"An in-process and in-memory PubSub, Broadcast, EventBus or Fanout implementation with type-safe topics implemented with generics. Respects context.","archived":false,"fork":false,"pushed_at":"2024-03-08T10:46:11.000Z","size":21,"stargazers_count":9,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-09T21:43:22.245Z","etag":null,"topics":["event-bus","event-sourcing","eventbus","eventsourcing","fanout","generics","in-process","pub-sub","pubsub","type-safe"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/egemengol.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-02-25T17:49:15.000Z","updated_at":"2024-10-18T17:12:26.000Z","dependencies_parsed_at":"2024-02-25T18:49:43.298Z","dependency_job_id":"991f30b9-3dbd-4213-a241-a511b4db7f6b","html_url":"https://github.com/egemengol/spread","commit_stats":null,"previous_names":["egemengol/goevents"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/egemengol/spread","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/egemengol%2Fspread","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/egemengol%2Fspread/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/egemengol%2Fspread/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/egemengol%2Fspread/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/egemengol","download_url":"https://codeload.github.com/egemengol/spread/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/egemengol%2Fspread/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28424001,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T13:30:50.153Z","status":"ssl_error","status_checked_at":"2026-01-14T13:29:08.907Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["event-bus","event-sourcing","eventbus","eventsourcing","fanout","generics","in-process","pub-sub","pubsub","type-safe"],"created_at":"2026-01-14T14:50:30.451Z","updated_at":"2026-01-14T14:50:31.253Z","avatar_url":"https://github.com/egemengol.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Spread\n\n[![GoDoc](https://godoc.org/github.com/egemengol/spread?status.svg\u0026style=flat-square)](http://godoc.org/github.com/egemengol/spread)\n[![GitHub](https://img.shields.io/badge/GitHub-100000?style=for-the-badge\u0026logo=github\u0026logoColor=white)](https://github.com/egemengol/spread)\n\nAn in-process and in-memory PubSub, Broadcast, EventBus or Fanout implementation with type-safe topics implemented with generics. Respects context.\n\n### Subscriber Patterns\n\nThese patterns can be used for a given topic at the same time with multiple instances.\n\n#### Channel-based\nEvery `recvChan` gets its own channel for reading.\n```golang\nvar topic *spread.Topic[int]\n\nrecvChan, removeRecvChan, err := topic.GetRecvChannel(20)\nfor number := range recvChan {\n    fmt.Printf(\"Got from channel: %d\\n\", number)\n}\n```\n\n#### Asynchronous\n\n```golang\nvar topic *spread.Topic[int]\n\ntopic.HandleAsync(func(_ctx context.Context, number int) {\n    fmt.Printf(\"Handling in async handler: %d\\n\", number)\n})\n```\n\n#### Synchronous\n\nThis blocks the topic's progress so better to keep it non-blocking.\n```golang\nvar topic *spread.Topic[int]\n\ntopic.HandleSync(func(number int) {\n    fmt.Printf(\"Handling in sync handler: %d\\n\", number)\n})\n```\n\n### Performance Characteristics\n\n- Every topic has a inbound channel with a dedicated goroutine for broadcasting.\n- Synchronous handlers in `HandleSync` get executed in this goroutine.\n- Asynchronous handlers or receiver channels that cannot keep up (with full buffers) get eliminated from the subscribers.\n- Publishing is the same as sending to a buffered channel, blocks when full.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fegemengol%2Fspread","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fegemengol%2Fspread","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fegemengol%2Fspread/lists"}