Merge branch 'patch-1' of https://github.com/mr-c/arvados into mr-c-patch-1
[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         "git.arvados.org/arvados.git/sdk/go/arvados"
11 )
12
13 // A ClientPool is a pool of ArvadosClients. This is useful for
14 // applications that make API calls using a dynamic set of tokens,
15 // like web services that pass through their own clients'
16 // credentials. See arvados-git-httpd for an example, and sync.Pool
17 // for more information about garbage collection.
18 type ClientPool struct {
19         // Initialize new clients by copying this one.
20         Prototype *ArvadosClient
21
22         pool      *sync.Pool
23         lastErr   error
24         setupOnce sync.Once
25 }
26
27 // MakeClientPool returns a new empty ClientPool, using environment
28 // variables to initialize the prototype.
29 func MakeClientPool() *ClientPool {
30         return MakeClientPoolWith(nil)
31 }
32
33 // MakeClientPoolWith returns a new empty ClientPool with a previously
34 // initialized arvados.Client.
35 func MakeClientPoolWith(client *arvados.Client) *ClientPool {
36         var err error
37         var proto *ArvadosClient
38
39         if client == nil {
40                 proto, err = MakeArvadosClient()
41         } else {
42                 proto, err = New(client)
43         }
44         return &ClientPool{
45                 Prototype: proto,
46                 lastErr:   err,
47         }
48 }
49
50 func (p *ClientPool) setup() {
51         p.pool = &sync.Pool{New: func() interface{} {
52                 if p.lastErr != nil {
53                         return nil
54                 }
55                 c := *p.Prototype
56                 return &c
57         }}
58 }
59
60 // Err returns the error that was encountered last time Get returned
61 // nil.
62 func (p *ClientPool) Err() error {
63         return p.lastErr
64 }
65
66 // Get returns an ArvadosClient taken from the pool, or a new one if
67 // the pool is empty. If an existing client is returned, its state
68 // (including its ApiToken) will be just as it was when it was Put
69 // back in the pool.
70 func (p *ClientPool) Get() *ArvadosClient {
71         p.setupOnce.Do(p.setup)
72         c, ok := p.pool.Get().(*ArvadosClient)
73         if !ok {
74                 return nil
75         }
76         return c
77 }
78
79 // Put puts an ArvadosClient back in the pool.
80 func (p *ClientPool) Put(c *ArvadosClient) {
81         p.setupOnce.Do(p.setup)
82         p.pool.Put(c)
83 }