13959: Merge branch 'master' into 13959-timeouts-and-logging
[arvados.git] / sdk / go / arvadosclient / pool.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: Apache-2.0
4
5 package arvadosclient
6
7 import (
8         "sync"
9 )
10
11 // A ClientPool is a pool of ArvadosClients. This is useful for
12 // applications that make API calls using a dynamic set of tokens,
13 // like web services that pass through their own clients'
14 // credentials. See arvados-git-httpd for an example, and sync.Pool
15 // for more information about garbage collection.
16 type ClientPool struct {
17         // Initialize new clients by coping this one.
18         Prototype *ArvadosClient
19
20         pool      *sync.Pool
21         lastErr   error
22         setupOnce sync.Once
23 }
24
25 // MakeClientPool returns a new empty ClientPool, using environment
26 // variables to initialize the prototype.
27 func MakeClientPool() *ClientPool {
28         proto, err := MakeArvadosClient()
29         return &ClientPool{
30                 Prototype: proto,
31                 lastErr:   err,
32         }
33 }
34
35 func (p *ClientPool) setup() {
36         p.pool = &sync.Pool{New: func() interface{} {
37                 if p.lastErr != nil {
38                         return nil
39                 }
40                 c := *p.Prototype
41                 return &c
42         }}
43 }
44
45 // Err returns the error that was encountered last time Get returned
46 // nil.
47 func (p *ClientPool) Err() error {
48         return p.lastErr
49 }
50
51 // Get returns an ArvadosClient taken from the pool, or a new one if
52 // the pool is empty. If an existing client is returned, its state
53 // (including its ApiToken) will be just as it was when it was Put
54 // back in the pool.
55 func (p *ClientPool) Get() *ArvadosClient {
56         p.setupOnce.Do(p.setup)
57         c, ok := p.pool.Get().(*ArvadosClient)
58         if !ok {
59                 return nil
60         }
61         return c
62 }
63
64 // Put puts an ArvadosClient back in the pool.
65 func (p *ClientPool) Put(c *ArvadosClient) {
66         p.setupOnce.Do(p.setup)
67         p.pool.Put(c)
68 }