Code Monkey home page Code Monkey logo

Comments (6)

matryer avatar matryer commented on July 1, 2024 1

re context, I tried implementing it in nsq and sadly it failed for some reason. See context branch if interested.

Tbh, I'm not too worried about it having an explicit Stop function; so unless it's trivial to implement, I'll probably end up leaving it. If anyone feels strongly either way, you are more than welcome to have a look.

from vice.

matryer avatar matryer commented on July 1, 2024

@HeavyHorst @GeorgeMac What do you think?

from vice.

GeorgeMac avatar GeorgeMac commented on July 1, 2024

Have you considered removing the concept of stopping and signaling finished from the interface altogether? Often this detail is implementation specific and not crucial to core functionality of interfacing with a queue.

When an implementation of the interface is instantiated, take for example the NSQ implementation (https://github.com/matryer/vice/blob/master/queues/nsq/nsq.go#L50) you return a pointer to the struct type. So you can still have concurrency control semantics on there, like a Stop or a Done func. But you can also omit them where necessary. You then don't need to pollute the interface. The interface should be designed from the consumers perspective. Not the programmer, but the code that interfaces with the Send and Receive functions. Most concrete code that would consume this interface should be focussed on send and receiving or maybe even just one of those semantics.

You could go as far as to say:

type Sender interface{
    Send(ctxt context.Context, name string, msgs <-chan []byte)
}

type Receiver interface{
    Receive(ctxt context.Context, name string) <-chan []byte
}

Where on Send ctxt.Done() should be closed when it has stopped consuming from msgs chan. Which you can assert in your test harness.

Again though, this is dependent on your audience. Is this repo to be a set of small interface contracts for queue adapters to be written against. Or is it more educational and have a single interface which defines a contract that all users should be aware of (sending, receiving, errors on those operations, graceful shutdown).

I hope this is useful and not completely missing the point πŸ‘

from vice.

matryer avatar matryer commented on July 1, 2024

from vice.

HeavyHorst avatar HeavyHorst commented on July 1, 2024

I see one problem if we put the context into the Send and Receive methods.

Receive(ctx context.Context, name string) <-chan []byte
Send(ctx context.Context, name string) chan<- []byte

Send and Receive reuses the channels so it could get tricky to unsubscribe the right ones.

ctx1, cancel1 := context.WithCancel(context.Background())
ctx2, cancel2 := context.WithCancel(context.Background())

// same channels
chan1 := transport.Receive(ctx1, "vicechannel1")
chan2 := transport.Receive(ctx2, "vicechannel1")

cancel2() //this should do nothing because transport.Receive(ctx1, "vicechannel1") is still active

We could have a context passed in to the New functions of the transport implementations to handle stopping, instead of a Stop function.

I think we'd still want Done() because it's important that the implementations are given enough time to properly de-register their interest in the underlying queue. Or is there a more elegant way to do that?

I think this approach is fine.

from vice.

GeorgeMac avatar GeorgeMac commented on July 1, 2024

Depends on the intention of Receive. You actually make this distinction in your other issue #19

Depending on the message semantics. The result of calling Receive could be a subscription to every message or a subset of the stream as in a work queue. If you made the default that every call to Receive gave you a subscription, you can still distribute work by sharing that resulting channel.
By forcing the same semantics as a channel on the Receive action, you are limiting consumers of this API to that messaging pattern. If they want copy the stream, doing so will require they implement it on top of a channel. Whereas if receive was a distinct subscription it is trivial to get work queue behaving by sharing the queue.

However, this abstraction might not make sense for both types of message queue. Maybe it shouldn't be painted with the same brush and they should be separate interfaces?

from vice.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.