简体   繁体   中英

How to share data between 2 different API calls?

I am trying to create a framework in which I would receive requests over REST API and would wait for another service (which works over gRPC) to poll and execute the request. This is needed cause the "other" service is very deeply embedded into the network and I can't directly call it. At the same time, I would like to buffer the output of the other service back to the request origin.

Any ideas how I can share this data between 2 different asynchronous API requests? Using the file system is a way... but I was thinking can I do it better via channels or something...?

Kind of pseudo code below:

func RestHandler(payload string) (string, error){
    respChan := make(chan string)
    workId := placeWorkInQueue(payload)
    // Start polling in the background
    go pollForResult(respChan, workId)
    // wait for result in the channel
    var result string
    select {
    case result = <-respChan:
        // implement your timeout logic as a another case: here
    }
    return result, nil
}

// This is poller for just the workId given to it.
func pollForResult(respChan chan string, workId string) {
    // Do the polling for workId result 
    /// Write response to respChan when available 
    // You may have to implement a timeout to give up polling.

}

func placeWorkInQueue(s string) string {
    // Place the job in queue and return a unique workId
    return "unique-id"
}

Use Redis queues in both directions. The API endpoint writes request and unique id to queue, registers Go channel with unique id as key with central reader in process, and waits on Go channel.

Queue reader gets responses with id from Redis queue and sends response to appropriate Go channel.

// Response represents the response type from the
// remote service.
type Response struct {
    ID string
    // ... more fields as needed
}

// Request represents request to remote serivce.
type Request struct {
    ID string
    // ... more fields as needed
}

// enqueueRequest writes request to Redis queue.
// Implementation TBD by application.
func enqueueRequest(r *Request) error {
    return nil
}

// dequeueResponse reads a response from a Redis queue.
// Implementation TBD by application.
func dequeueResponse() (*Response, error) {
    return nil, nil
}

Use sync.Map to register waiting Go channels from API request handlers. The key is the unique id for the request and the value is a chan *Response .

  var responseWaiters sync.Map

Run queuePump in a single goroutine to dequeue results from Redis queue and send to appropriate channel. Start the gorountine before serving HTTP requests.

func queuePump() {
    for {
        response, err := dequeueResponse()
        if err != nil {
            // handle error
        }
        v, ok := responseWaiters.Load(response.ID)
        if ok {
            c := v.(chan *Response)
            c <- response

            // Remove cahnel from map to ensure that pump never sends 
            // twice to same channel. The pump will black forever if
            // this happens. 
            responseWaiters.Delete(response.ID)
        }
    }
}

The API endpoint allocates a unique id for request, registers a channel with the queue pump, enqueues the request and waits for the response.

func apiEndpoint(w http.ResponseWriter, r *http.Request) {
    id := generateUniqueID()

    c := make(chan *Response, 1) // capacity 1 ensures that queue pump will not block
    responseWaiters.Store(id, c)
    defer responseWaiters.Delete(id)

    req := &Request{
        ID: id,
        // fill in other fields as needed
    }

    if err := enqueueRequest(req); err != nil {
        // handle error
    }

    select {
    case resp := <-c:
        // process response
        fmt.Println(resp)
    case <-time.After(10 * time.Second):
        // handle timeout error
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM