{"id":37121780,"url":"https://github.com/ksloveyuan/channelx","last_synced_at":"2026-01-14T14:01:07.580Z","repository":{"id":37411458,"uuid":"206991765","full_name":"Ksloveyuan/channelx","owner":"Ksloveyuan","description":"Some useful tools implemented by channel to increase development efficiency, e.g. event bus, promise, actor, stream, aggregator, goroutine pool, etc..","archived":false,"fork":false,"pushed_at":"2021-09-21T14:17:12.000Z","size":68,"stargazers_count":87,"open_issues_count":1,"forks_count":18,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-06-20T12:06:04.694Z","etag":null,"topics":["actor","concurrency","eventbus","golang","promise","stream"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Ksloveyuan.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}},"created_at":"2019-09-07T16:00:39.000Z","updated_at":"2024-01-16T14:21:35.000Z","dependencies_parsed_at":"2022-07-12T12:50:47.549Z","dependency_job_id":null,"html_url":"https://github.com/Ksloveyuan/channelx","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/Ksloveyuan/channelx","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ksloveyuan%2Fchannelx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ksloveyuan%2Fchannelx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ksloveyuan%2Fchannelx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ksloveyuan%2Fchannelx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Ksloveyuan","download_url":"https://codeload.github.com/Ksloveyuan/channelx/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ksloveyuan%2Fchannelx/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28422402,"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":["actor","concurrency","eventbus","golang","promise","stream"],"created_at":"2026-01-14T14:01:06.548Z","updated_at":"2026-01-14T14:01:07.572Z","avatar_url":"https://github.com/Ksloveyuan.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# channelx\n[![Go Report Card](https://goreportcard.com/badge/github.com/Ksloveyuan/channelx)](https://goreportcard.com/report/github.com/Ksloveyuan/channelx)\n[![build](https://api.travis-ci.org/Ksloveyuan/channelx.svg?branch=master)](https://api.travis-ci.org/Ksloveyuan/channelx.svg?branch=master)\n[![codecov](https://codecov.io/gh/Ksloveyuan/channelx/branch/master/graph/badge.svg)](https://codecov.io/gh/Ksloveyuan/channelx)\n[![GoDoc](https://godoc.org/github.com/Ksloveyuan/channelx?status.svg)](https://godoc.org/github.com/Ksloveyuan/channelx)\n\nSome useful tools implemented by channel to increase development efficiency, e.g. event bus, stream, promise, actor, parallel runner, aggregator, etc..\n\n# blogs\n- [如何把Golang的channel用的如nodejs的stream一样丝滑](https://juejin.im/post/5d7ba76ef265da03be490856)\n- [如何用Golang的channel实现消息的批量处理](https://juejin.im/post/5d8c6775e51d45781332e91f)\n- [如何把Golang的Channel玩出async和await的feel](https://juejin.im/post/5e4175a36fb9a07ca80a9c77)\n- [下次想在Golang中写个并发处理，就用这个模板，准没错！](https://juejin.cn/post/6959369791937347621/)\n- [玩转Golang的channel，二百行代码实现PubSub模式](https://juejin.cn/post/7010383321674809352)\n\n## Parallel runner\nA simple util to run tasks in parallel\n```golang\nworker := func(ctx context.Context, input interface{}) (interface{}, error) {\n    num := input.(int)\n    return num+1, nil\n}\n\ninputs := []interface{}{1,2,3,4,5}\noutputs, err := channelx.RunInParallel(context.Background(), inputs, worker, 4)\n```\nmore examples, please check [parallel_runner_test.go](https://github.com/Ksloveyuan/channelx/blob/master/parallel_runner_test.go)\n\n### EventBus\nA PubSub pattern util\n\n```golang\nlogger := channelx.NewConsoleLogger()\neventBus := channelx.NewEventBus(logger,  4,4,2, time.Second, 5 * time.Second)\neventBus.Start()\n\nhandler := NewExampleHandler(logger)\neventBus.Subscribe(ExampleEventID, handler)\neventBus.Publish(NewExampleEvent())\n\neventBus.Stop()\n```\nmore details, please check [event_bus_test.go#TestEventBus_Example](https://github.com/Ksloveyuan/channelx/blob/master/event_bus_test.go#L103)\n\n## Promise\nA golang style async/await, even I call it Promise, while the api is not 100% aligns with Javascript Promise.\n\n```golang\npromise := NewPromise(func() (res interface{}, err error) {\n    // do work asynchronously here\n    reuturn\n}).Then(func(input interface{}) (interface{}, error) {\n    // here is the succss handler, which aslo runs asynchronously \n}, func(err error) interface{} {\n    // here is the error handler, which aslo runs asynchronously \n})\n\n// await: wait until it completes.\nres, _ := promise.Done()\n```\nmore examples, please check [promise_test.go](https://github.com/Ksloveyuan/channelx/blob/master/promise_test.go)\n\n## Actor\nThe actor pattern is also called as Active Object, it seems like Promise, but the difference is Actor can be reused, and it is FIFO.\n\n```golang\nactor := NewActor(SetActorBuffer(0))\ndefer actor.Close()\n\n// do some work asynchroniously.\ncall := actor.Do(func() (interface{}, error) {\n    time.Sleep(0 * time.Second)\n    return 0, nil\n})\n\n// can to some other synchroniouse work here\n// ......\n\n// wait for the call completes.\nres, err := call.Done()\n```\nmore examples, please check [actor_test.go](https://github.com/Ksloveyuan/channelx/blob/master/actor_test.go)\n\n## Stream\nSteam works like Node.Js stream, it can be piped and data flows through the pipe one by one.\n\n### before\n```golang\nvar multipleChan = make(chan int, 4)\nvar minusChan = make(chan int, 4)\nvar harvestChan = make(chan int, 4)\n\ndefer close(multipleChan)\ndefer close(minusChan)\ndefer close(harvestChan)\n\ngo func() {\n    for i:=1;i\u003c=100;i++{\n        multipleChan \u003c- i\n    }\n}()\n\nfor i:=0; i\u003c4; i++{\n    go func() {\n        for data := range multipleChan {\n            minusChan \u003c- data * 2\n            time.Sleep(10* time.Millisecond)\n        }\n    }()\n\n    go func() {\n        for data := range minusChan {\n            harvestChan \u003c- data - 1\n            time.Sleep(10* time.Millisecond)\n        }\n    }()\n}\n\nvar sum = 0\nvar index = 0\nfor data := range harvestChan{\n    sum += data\n    index++\n    if index == 100{\n        break\n    }\n}\n\nfmt.Println(sum)\n```\n\n### after\n\n```golang\nvar sum = 0\n\nNewChannelStream(func(seedChan chan\u003c- Item, quitChannel chan struct{}) {\n    for i:=1; i\u003c=100;i++{\n        seedChan \u003c- Item{Data:i}\n    }\n    close(seedChan) //don't forget to close it\n}).Pipe(func(Item Item) Item {\n    return Item{Data: Item.Data.(int) * 2}\n}).Pipe(func(Item Item) Item {\n    return Item{Data: Item.Data.(int) - 1}\n}).Harvest(func(Item Item) {\n    sum += Item.Data.(int)\n})\n\nfmt.Println(sum)\n```\n\nmore examples, please check [stream_test.go](https://github.com/Ksloveyuan/channelx/blob/master/stream_test.go)\n\n## Aggregator\nAggregator is used for the scenario that receives request one by one while handle them in a batch would increase efficiency.\n\n```golang\n// YourKnownType, YourBatchHandler, yourRequest are faked type or object\n\nbatchProcess := func(items []interface{}) error {\n    var arr YourKnownType \n    for _, item := range items{\n        ykt := item.(YourKnownType)\n        arr = append(arr, ykt)\n    }\n    \n    YourBatchHandler(arr)\n}\n\naggregator := NewAggregator(batchProcess)\n\naggregator.Start()\n\naggregator.Enqueue(yourRequest)\n\naggregator.Stop()\n```\nmore examples, please check [aggregator_test.go](https://github.com/Ksloveyuan/channelx/blob/master/aggregator_test.go)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fksloveyuan%2Fchannelx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fksloveyuan%2Fchannelx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fksloveyuan%2Fchannelx/lists"}