reactivex / rxgo Goto Github PK
View Code? Open in Web Editor NEWReactive Extensions for the Go language.
License: MIT License
Reactive Extensions for the Go language.
License: MIT License
RxGo was created by @jochasinga being born within your personal GitHub account, as the project evolved it was moved to Reactivex organization.
Before being moved to Reactivex organization, @jochasinga created the reactivex-go/Lobby channel for communication.
How RxGo is an official Reactivex project what do you think of moving the gitter.im channel to the Reactivex organization[1]?
Hi,
first of all, great initiative. Rx is something that should definitely be implemented in Go.
There should be maybe some kind of panic error handling in handlers. For example, basic implementation would be something like:
// OnNext applies Observer's NextHandler to an Item
func (ob Observer) OnNext(item interface{}) {
defer func() {
if (recover() != nil) {
ob.OnError(errors.New(7, "Panicked!"))
}
}()
switch item := item.(type) {
case error:
return
default:
if ob.NextHandler != nil {
ob.NextHandler(item)
}
}
}
A better approach would be an optional panic handler, as the deffer is not very performant.
u
This test will fail once every few times here.
Iterable
should be moved to an interface. This is the latest type we have to handle for the v2.
When running the tests with the -race
flag, there is a warning about a data race:
$ go test -race ./...
? github.com/reactivex/rxgo [no test files]
ok github.com/reactivex/rxgo/connectable (cached)
ok github.com/reactivex/rxgo/errors (cached)
? github.com/reactivex/rxgo/examples/reactive_sum [no test files]
? github.com/reactivex/rxgo/examples/scroll [no test files]
? github.com/reactivex/rxgo/fx [no test files]
ok github.com/reactivex/rxgo/handlers (cached)
ok github.com/reactivex/rxgo/iterable (cached)
ok github.com/reactivex/rxgo/observable (cached)
ok github.com/reactivex/rxgo/observer (cached)
==================
WARNING: DATA RACE
Read at 0x00c0000a4500 by goroutine 7:
github.com/reactivex/rxgo/subscription.TestSubscription()
/Users/tobi/go/src/github.com/ReactiveX/RxGo/subscription/subscription_test.go:30 +0x369
testing.tRunner()
/usr/local/Cellar/go/1.11/libexec/src/testing/testing.go:827 +0x162
Previous write at 0x00c0000a4500 by goroutine 8:
github.com/reactivex/rxgo/subscription.TestSubscription.func1()
/Users/tobi/go/src/github.com/ReactiveX/RxGo/subscription/subscription_test.go:22 +0x67
Goroutine 7 (running) created at:
testing.(*T).Run()
/usr/local/Cellar/go/1.11/libexec/src/testing/testing.go:878 +0x650
testing.runTests.func1()
/usr/local/Cellar/go/1.11/libexec/src/testing/testing.go:1119 +0xa8
testing.tRunner()
/usr/local/Cellar/go/1.11/libexec/src/testing/testing.go:827 +0x162
testing.runTests()
/usr/local/Cellar/go/1.11/libexec/src/testing/testing.go:1117 +0x4ee
testing.(*M).Run()
/usr/local/Cellar/go/1.11/libexec/src/testing/testing.go:1034 +0x2ee
main.main()
_testmain.go:44 +0x221
Goroutine 8 (finished) created at:
github.com/reactivex/rxgo/subscription.TestSubscription()
/Users/tobi/go/src/github.com/ReactiveX/RxGo/subscription/subscription_test.go:21 +0xb1
testing.tRunner()
/usr/local/Cellar/go/1.11/libexec/src/testing/testing.go:827 +0x162
==================
--- FAIL: TestSubscription (0.01s)
testing.go:771: race detected during execution of test
FAIL
FAIL github.com/reactivex/rxgo/subscription 0.031s
u
We should add in the tests performed by Travis the -race
option.
Have any intresst on scheduler implementation in Repeat Operator ?
One usefull usescase can be to call every 5 minute a rest api.
I would try to implement it.
func Repeat(item interface{},cronspec string) Observable
schedulerstream := Repeat("http://www.example.com", "@every 5m")
reponsestream := schedulerstream.Map('...make httpcall...')
and
schedulerstream := Repeat("http://www.example.com", "*/5 * * * *")
reponsestream := schedulerstream.Map('...make httpcall...')
Hey,
I would like to implement the All operator. According to RxJava: this operator determines whether all items emitted by an Observable meet some criteria.
My question is what would be returned by the All
method? Different options:
Observable
to return a single bool.type SingleBool <-chan bool
type Single <-chan interface{}
I feel like it's important to share a common understanding between the project maintainers and committers. This would really help to boost the project :)
Package upgrade signature, required context on new version
Ref
https://travis-ci.org/ReactiveX/RxGo/jobs/448246104
Coming from other ReactiveX language bindings, it's confusing not to find a direct Subject equivalent.
The only documentation is reading the source of Observable
and realizing it's a wrapper for <-chan interface{}
and figuring it out from there, or coming across @jochasinga's comment on issue #39.
Hello,
I have a question about the usage of rxgo.
When using rxjs I usually use Subjects and .asObservable to get a simple event pattern. However in rxgo there is no Subject (yet?) and from the tutorials I could not find any way to pass data at runtime.
In the tutorials all observers are generated from existing arrays or functions which provide data, however Usually I would do something like this:
type MyStruct struct {
s subject.Subject
}
func NewMyStruct() MyStruct {
m := MyStruct{}
m.s = subject.New()
return s
}
func (m *MyStruct) doSomeActionWithNewValue(value interface{}) {
m.s.Next(value)
}
func(m *MyStruct) getObservable() observable.Observable {
return m.s.AsObservable()
}
func main() {
myStruct := NewMyStruct()
myStruct.getObservable().Subscribe(func(value interface{}) {
// do work here
}
myStruct.doSomeActionWithNewValue("hello world")
}
Is it just because subjects are not yet implemented or is it intended to do something like this in a totally different way in go?
I already tried using a channel as base for the observable and using closures to provide a provider function for the observable, but both resulted in go telling me, that my application deadlocked, when waiting for the subscriptions.
The
Zip
method returns an Observable that applies a function of your choosing to the combination of items emitted, in sequence, by two (or more) other Observables, with the results of this function becoming the items emitted by the returned Observable. It applies this function in strict sequence, so the first item emitted by the new Observable will be the result of the function applied to the first item emitted by Observable #1 and the first item emitted by Observable #2; the second item emitted by the new zip-Observable will be the result of the function applied to the second item emitted by Observable #1 and the second item emitted by Observable #2; and so forth. It will only emit as many items as the number of items emitted by the source Observable that emits the fewest items.
reference http://reactivex.io/documentation/operators/zip.html
Due to Observable
being only a simple <-chan interface{}
wrapper, items sent to the channel will only be received by one of the subscribed Observer
s.
The expected behavior would be for every Observer
to receive the same items sent to the underlying channel. This is how it works in other ReactiveX implementations.
As the example code:
subscription := observable.Subscribe(observer)
The Subscribe function will return a disposable in other Rx implementations such as RxSwift, RxJS etc.
But in RxGo, I think that shouldn't return a subscription when call Subscribe.
In sources, I found that an observable is a chan. I think that it's an error prototype. Thinking that we want to implement the operators "Materialize/Dematerialize" or "Combine/Merge/Concat" or "Catch". The observable should process error event, next event and completed event.
code proposal:
dispose := observable.Create(func(o observer.Observer) disposable.Disposable{ // create a network request // ............. return disposable.Disposable(func(){ // cancel network request. }) })
Sorry for my poor english.
The ReactiveX has an RxGo project which doesn't have any code. How about contributing this code there?
We need a way to create an Observable that 'lazily' emits items only when subscribed to.
Implement the defer() function as described in Rx: http://reactivex.io/documentation/operators/defer.html
(Is there any way the current code base emit items only when subscribed to?)
observable.Subscribe()
should be reimplemented so it's non-blocking (see this test case).
Need to update the README.md example
ref #99
Hello there!
I was dusting off some old projects and I stumbled upon this https://github.com/thenikso/gorx from 2014
To be honest I don't quite remember what I was doing there ๐ however I kind of remember I did some work to support go routines quite nicely.
I don't know maybe it is something you might want to take a look at, that's all.
Best (and feel free to close this)
The signature should comply with Rx standards. Moreover, there's now a mechanism to dispose of a subscription. It's not necessary to do something specific for this operator.
fx types are coupled to a given operator. For example, a function taking two interfaces as an argument and returning an interface is defined this way:
// ScannableFunc defines a function that acts as a predicate to the Scan operator.
ScannableFunc func(interface{}, interface{}) interface{}
My opinion is that those types should be as generic as possible. For example, if we need to implement a zip operator, we can't reuse the same type as it's tied to the scan operator. So we'll have to duplicate the code and create a ZipableFunc func(interface{}, interface{}) interface{}
. I don't really like this approach.
If we take a look at RxJava for instace, there is an interface called BiFunction
. What about reusing these conventions rather?
Add
func CombineLatest(o ...Observable,map func (is []interface{}) interface{}) Observable
Add filters:
func (o Observable) Skip(nth uint) Observable
func (o Observable) SkipLast(nth uint) Observable
ObserverMock
and mockDuration
)As per contribution guidelines, I'm opening an issue for discussion regarding the implementation of Retry.
Per Documentation:
The Retry operator responds to an onError notification from the source Observable by not passing that call through to its observers, but instead by resubscribing to the source Observable and giving it another opportunity to complete its sequence without error. Retry always passes onNext notifications through to its observers, even from sequences that terminate with an error, so this can cause duplicate emissions (as shown in the diagram above)
I have an implementation of Retry
on my for, as linked below
reference: http://reactivex.io/documentation/operators/retry.html
location: https://github.com/ReactiveX/RxGo/wiki
ref #57
In v1 we introduced a mechanism to pass options to operators. We need to generalize this for all the operators.
Right now it will panic
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference
Whenever an OnCompleted
handler isn't defined in an Observer
. (Try to comment this out to see what I mean).
Hi,
I was doing some testing and found package behaves strange with more than one observers connected to source.
A simple app is listening for Stdin and sends all the values into channel which is in turn connected with observers via iterable source. With this scenario app requires me to put values twice to have it processed. Am i doing something wrong?
func main() {
lines := make(chan interface{})
go func() {
defer close(lines)
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
lines <- scanner.Text()
}
}()
process := observer.Observer{
// Register a handler function for every next available item.
NextHandler: func(item interface{}) {
fmt.Printf("Processing: %v\n", item)
},
// Register a handler for any emitted error.
ErrHandler: func(err error) {
fmt.Printf("Encountered error: %v\n", err)
},
// Register a handler when a stream is completed.
DoneHandler: func() {
fmt.Println("Done!")
},
}
isOne := func(str interface{}) bool {
return str == "one"
}
isTwo := func(str interface{}) bool {
return str == "two"
}
mapOne := func(str interface{}) interface{} {
return str
}
mapTwo := func(str interface{}) interface{} {
return str
}
it, err := iterable.New(lines)
if err != nil {
fmt.Printf(err.Error())
}
src := observable.From(it)
pipe1 := src.Filter(isOne).Map(mapOne).Subscribe(process)
pipe2 := src.Filter(isTwo).Map(mapTwo).Subscribe(process)
select {
case <-pipe1:
case <-pipe2:
}
}
Hello there!
When I read the source code, I am confused about the way the signal is handled:
go func(ob observer.Observer) {
<-fin
if sub.Error == nil {
ob.OnDone()
sub.Unsubscribe()
}
go func() {
temp <- sub // Because no one reads sub, so it will be blocked here
fmt.Println("test") // The code can not be executed here.
done <- temp // So temp will not be sent to done, it is impossible for others to read the temp from done.
}()
wg.Done()
}(ob)
But when I run the test program, it passes the test.
func TestDoOperator(t *testing.T) {
co := Just(1, 2, 3)
num := 0
nextf := func(item interface{}) {
num += item.(int)
}
co = co.Do(nextf)
sub := co.Connect()
v := <-sub
fmt.Println("v --->", v)
assert.Equal(t, 6, num)
}
It prints out the result is:
v ---> <nil>
Do not know if I have a clear expression, why is this handled? Hope to get help, thank you for your answer.
RxJava and other have implemented the variant called Single
:
http://reactivex.io/documentation/single.html
I believe since golang is heavily used in developing Restful APIs the Single
pattern will be really effective in developing microservices
where to satisfy a single Rest call the server has to actual coordinate with multiple backends. In this scenario the Single
patter will allow for asynchronous handling of Rest requests, making the code a lot more declarative.
@mattpodwysocki I need to add a collaborator @avelino to this project. He will help me maintain it.
Add Take
and TakeLast
filter.
func (o Observable) Take(n int) Observable
func (o Observable) TakeLast(n int) Observable
http://reactivex.io/documentation/operators/take.html
http://reactivex.io/documentation/operators/takelast.html
A propose to add the buffer operator. See: http://reactivex.io/documentation/operators/buffer.html
An signature to match the syntax of the other languages could look like this:
func (o Observable) Buffer(boundary Observable) Observable {}
// skip should be optional
func (o Observable) BufferWithCount(count int, skip ...int) Observable {}
// timeshift should be optional
func (o Observable) BufferWithTime(timespan time.Duration, timeshift ...time.Duration) Observable {}
func (o Observable) BufferWithTimeOrCount(timespan time.Duration, count int) Observable {}
For the moment, I omitted the case for opening and closing observables since it's more difficult to implement.
If there are no concerns about this, I can send a PR.
It would be great to have the window operator as well: http://reactivex.io/documentation/operators/window.html
I was looking for a sliding window in go and reactivex is a good place to have such feature.
Thumbs up!
@mattpodwysocki can we resolve on this?
I have limited experience with it, but I've often read that there is a cost associated with the use of the empty interface in the boxing and unboxing. If you use reactivex in the data access layer and basically all your data is filtered by it, or at least the filtered/indexed fields, is there a noticeable impact to be observed by it's use? I usually just use the explicit data types, but I recognize where interface{}
is useful. I used it to generate json in my JsonBuilder
package as it would have been basically impossible otherwise.
As per contribution guidelines, I'm opening an issue for discussion regarding the implementation of Flatmap.
Per Documentation:
The FlatMap operator transforms an Observable by applying a function that you specify to each item emitted by the source Observable, where that function returns an Observable that itself emits items. FlatMap then merges the emissions of these resulting Observables, emitting these merged results as its own sequence.
A naive implementation could look like
func (o Observable) FlatMap(apply fx.FlatMappableFunc) Observable {
out := make(chan interface{})
go func() {
for item := range o {
go func(sub Observable) {
handler := observer.Observer{
NextHandler: func(i interface{}) {
out <- i
},
ErrHandler: func(err error) {
out <- err
},
}
s := sub.Subscribe(handler)
<-s
}(apply(item))
}
close(out)
}()
return Observable(out)
}
I see that the dev
branch has a Merge
function, however I'm not sure how to exploit the underlying reflect.SelecCase
with a dynamic number of Observables. Creating a subscriber (and a go routine) for each element seems sub-optimal, but out of the top of my head I'm not aware of a different solution.
I'd be happy to submit a PR once agreement of the implementation is reached.
Have any one interest of Repeat Creating Operator? I would try to implement it.
http://reactivex.io/documentation/operators/repeat.html
Repeat
create an Observable that emits a particular item multiple times.
The Repeat operator emits an item repeatedly. Some implementations of this operator allow you to repeat a sequence of items, and some permit you to limit the number of repetitions.
func Repeat() Observable
func Repeat(ntimes int) Observable
Hi,
I've tried to create TestObserver to simplify testing process.
type TestObserver{ observer.Observer }
Unfortunately there was no way to subscribe custom observer (TestObserver in my case). Working code looked like that:
sequence.subscribe(testObserver.Observer)
I scrutinized source code and saw that Observer is a struct. If observer would be interface then there will be no issue. I made a try of Observer interface introduction.
I replaced Observer with wrappingObserver (private to keep one entry point - New function in observer package). Then introduced Observer interface. There was no need to keep rx.EventHandler - handlers conversion in kept in handlers package.
If you consider the proposal is valid, please take a look at: https://github.com/venth/RxGo/tree/introduction-of-observer-interface
I stored there afore mentioned changes.
This issue is a placeholder to discuss the future v2 release.
I know for example migrating Observable
, Observer
etc. should be part of the v1 according to this card: https://github.com/ReactiveX/RxGo/projects/1#card-6433015
Yet, if we do that it will not be backward compatible anymore with the existing API. For example, an user cannot wait anymore on the end of an Observable
by doing a:
<-myObservable
Regarding the v2, I've started to implement few stuf which are part of this PR: #95. In a nutshell, it contains a migration of the main types into interfaces, a creation of new types (Optional
, Single
etc.) and new operators. Is this PR going in the right direction for the v2?
What else should we include?
Furthermore, what are the plans for the v2 in terms of scheduling? Shall we release something before or after Go 2?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.