@@ -45,6 +45,11 @@ type Client struct {
45
45
rawClient * storage.BigQueryWriteClient
46
46
projectID string
47
47
48
+ // retained context. primarily used for connection management and the underlying
49
+ // client.
50
+ ctx context.Context
51
+ cancel context.CancelFunc
52
+
48
53
// cfg retains general settings (custom ClientOptions).
49
54
cfg * writerClientConfig
50
55
@@ -66,21 +71,27 @@ func NewClient(ctx context.Context, projectID string, opts ...option.ClientOptio
66
71
}
67
72
o = append (o , opts ... )
68
73
69
- rawClient , err := storage .NewBigQueryWriteClient (ctx , o ... )
74
+ cCtx , cancel := context .WithCancel (ctx )
75
+
76
+ rawClient , err := storage .NewBigQueryWriteClient (cCtx , o ... )
70
77
if err != nil {
78
+ cancel ()
71
79
return nil , err
72
80
}
73
81
rawClient .SetGoogleClientInfo ("gccl" , internal .Version )
74
82
75
83
// Handle project autodetection.
76
84
projectID , err = detect .ProjectID (ctx , projectID , "" , opts ... )
77
85
if err != nil {
86
+ cancel ()
78
87
return nil , err
79
88
}
80
89
81
90
return & Client {
82
91
rawClient : rawClient ,
83
92
projectID : projectID ,
93
+ ctx : cCtx ,
94
+ cancel : cancel ,
84
95
cfg : newWriterClientConfig (opts ... ),
85
96
pools : make (map [string ]* connectionPool ),
86
97
}, nil
@@ -103,6 +114,10 @@ func (c *Client) Close() error {
103
114
if err := c .rawClient .Close (); err != nil && firstErr == nil {
104
115
firstErr = err
105
116
}
117
+ // Cancel the retained client context.
118
+ if c .cancel != nil {
119
+ c .cancel ()
120
+ }
106
121
return firstErr
107
122
}
108
123
@@ -114,8 +129,11 @@ func (c *Client) NewManagedStream(ctx context.Context, opts ...WriterOption) (*M
114
129
}
115
130
116
131
// createOpenF builds the opener function we need to access the AppendRows bidi stream.
117
- func createOpenF (ctx context.Context , streamFunc streamClientFunc ) func (opts ... gax.CallOption ) (storagepb.BigQueryWrite_AppendRowsClient , error ) {
118
- return func (opts ... gax.CallOption ) (storagepb.BigQueryWrite_AppendRowsClient , error ) {
132
+ func createOpenF (streamFunc streamClientFunc , routingHeader string ) func (ctx context.Context , opts ... gax.CallOption ) (storagepb.BigQueryWrite_AppendRowsClient , error ) {
133
+ return func (ctx context.Context , opts ... gax.CallOption ) (storagepb.BigQueryWrite_AppendRowsClient , error ) {
134
+ if routingHeader != "" {
135
+ ctx = metadata .AppendToOutgoingContext (ctx , "x-goog-request-params" , routingHeader )
136
+ }
119
137
arc , err := streamFunc (ctx , opts ... )
120
138
if err != nil {
121
139
return nil , err
@@ -167,11 +185,11 @@ func (c *Client) buildManagedStream(ctx context.Context, streamFunc streamClient
167
185
if err != nil {
168
186
return nil , err
169
187
}
170
- // Add the writer to the pool, and derive context from the pool .
188
+ // Add the writer to the pool.
171
189
if err := pool .addWriter (writer ); err != nil {
172
190
return nil , err
173
191
}
174
- writer .ctx , writer .cancel = context .WithCancel (pool . ctx )
192
+ writer .ctx , writer .cancel = context .WithCancel (ctx )
175
193
176
194
// Attach any tag keys to the context on the writer, so instrumentation works as expected.
177
195
writer .ctx = setupWriterStatContext (writer )
@@ -218,7 +236,7 @@ func (c *Client) resolvePool(ctx context.Context, settings *streamSettings, stre
218
236
}
219
237
220
238
// No existing pool available, create one for the location and add to shared pools.
221
- pool , err := c .createPool (ctx , loc , streamFunc )
239
+ pool , err := c .createPool (loc , streamFunc )
222
240
if err != nil {
223
241
return nil , err
224
242
}
@@ -227,24 +245,28 @@ func (c *Client) resolvePool(ctx context.Context, settings *streamSettings, stre
227
245
}
228
246
229
247
// createPool builds a connectionPool.
230
- func (c * Client ) createPool (ctx context. Context , location string , streamFunc streamClientFunc ) (* connectionPool , error ) {
231
- cCtx , cancel := context .WithCancel (ctx )
248
+ func (c * Client ) createPool (location string , streamFunc streamClientFunc ) (* connectionPool , error ) {
249
+ cCtx , cancel := context .WithCancel (c . ctx )
232
250
233
251
if c .cfg == nil {
234
252
cancel ()
235
253
return nil , fmt .Errorf ("missing client config" )
236
254
}
237
- if location != "" {
238
- // add location header to the retained pool context.
239
- cCtx = metadata .AppendToOutgoingContext (ctx , "x-goog-request-params" , fmt .Sprintf ("write_location=%s" , location ))
240
- }
255
+
256
+ var routingHeader string
257
+ /*
258
+ * TODO: set once backend respects the new routing header
259
+ * if location != "" && c.projectID != "" {
260
+ * routingHeader = fmt.Sprintf("write_location=projects/%s/locations/%s", c.projectID, location)
261
+ * }
262
+ */
241
263
242
264
pool := & connectionPool {
243
265
id : newUUID (poolIDPrefix ),
244
266
location : location ,
245
267
ctx : cCtx ,
246
268
cancel : cancel ,
247
- open : createOpenF (ctx , streamFunc ),
269
+ open : createOpenF (streamFunc , routingHeader ),
248
270
callOptions : c .cfg .defaultAppendRowsCallOptions ,
249
271
baseFlowController : newFlowController (c .cfg .defaultInflightRequests , c .cfg .defaultInflightBytes ),
250
272
}
0 commit comments