Home > OS >  How to implement the query function
How to implement the query function

Time:07-31

I try to develop a program that reads from multiple replicated databases simultaneously. It must accept the response that arrives first. So the tsk is to implement the query function. I tried select, but the program gives an error and I think I'm going in the wrong direction. Can you tell me how to properly implement this program.

package main

import (
    "fmt"
    "time"
)

type Conn interface {
    DoQuery(query string) Result
}

type Result struct {
    Query    string
    ConnName string
}

type Conn1 struct{}
type Conn2 struct{}
type Conn3 struct{}

func (c Conn1) DoQuery(query string) Result {
    time.Sleep(1 * time.Second)
    return Result{Query: query, ConnName: "Conn1"}
}

func (c Conn2) DoQuery(query string) Result {
    time.Sleep(2 * time.Second)
    return Result{Query: query, ConnName: "Conn2"}
}

func (c Conn3) DoQuery(query string) Result {
    time.Sleep(3 * time.Second)
    return Result{Query: query, ConnName: "Conn3"}
}

func query(conns []Conn, query string) Result {
    // <- here is the beginning of code that I implemented
    ch1 := make(chan Conn1)
    ch2 := make(chan Conn2)
    ch3 := make(chan Conn3)

    select {
    case one := <-ch1:
        return one.DoQuery("First query")
    case two := <-ch2:
        return two.DoQuery("Second query")
    case three := <-ch3:
        return three.DoQuery("Third query")
    }
    // -> here is the end of code
}

func main() {
    conns := make([]Conn, 3)
    conns[0] = Conn1{}
    conns[1] = Conn2{}
    conns[2] = Conn3{}
    res := query(conns, "select * from users")
    fmt.Println(res)
}

CodePudding user response:

Run each query in a goroutine and send the result of each query to a single channel. Receive on the channel in the main goroutine to get the first result. See the commentary for more info.

func query(conns []Conn, query string) Result {
    // Create the channel to receive the first result. The capacity
    // len(conns)-1 ensures that all goroutines can send a value to the
    // channel and exit.
    ch := make(chan Result, len(conns)-1)

    // Start a goroutine to query on each connection. 
    // https://go.dev/doc/faq#closures_and_goroutines explains
    // why conn is passed as an argument.
    for _, conn := range conns {
        go func(conn Conn) {
            ch <- conn.DoQuery(query)
        }(conn)
    }

    // Wait for the the first result and return it.
    return <-ch
}

Run an example on the playground.

  • Related