@@ -29,13 +29,13 @@ perform basic insert operations.
2929
3030::: info
3131
32- This page focuses on our high-performance ingestion client, which is optimized for ** writing** data to QuestDB.
33- For retrieving data, we recommend using a [ PostgreSQL-compatible .NET library] ( /docs/pgwire/c-sharp/ ) or our
32+ This page focuses on our high-performance ingestion client, which is optimized
33+ for ** writing** data to QuestDB. For retrieving data, we recommend using a
34+ [ PostgreSQL-compatible .NET library] ( /docs/pgwire/c-sharp/ ) or our
3435[ HTTP query endpoint] ( /docs/reference/sql/overview/#rest-http-api ) .
3536
3637:::
3738
38-
3939## Requirements
4040
4141- .NET 6.0 or higher is required.
@@ -59,7 +59,7 @@ dotnet add package net-questdb-client
5959` Sender ` is single-threaded, and uses a single connection to the database.
6060
6161If you want to send in parallel, you can use multiple senders and standard async
62- tasking .
62+ tasks .
6363
6464:::
6565
@@ -97,11 +97,11 @@ using var sender = Sender.New("http::addr=localhost:9000;username=admin;token=<t
9797TCP authentication can be configured using JWK tokens:
9898
9999``` csharp
100- using var sender = Sender .New (" tcp::addr=localhost:9000 ;username=admin;token=<token>" );
100+ using var sender = Sender .New (" tcp::addr=localhost:9009 ;username=admin;token=<token>" );
101101```
102102
103- The connection string can also be built programatically. See
104- [ Configuration ] ( #configuration ) for details.
103+ The connection options can also be built programatically. See
104+ [ Ways to create the client ] ( #ways-to-create-the-client ) for details.
105105
106106## Basic insert
107107
@@ -127,8 +127,8 @@ await sender.Table("trades")
127127await sender .SendAsync ();
128128```
129129
130- In this case, the designated timestamp will be the one at execution time . Let's
131- see now an example with timestamps, custom auto-flushing, basic auth, and error
130+ In this case, we asked the server to assign the timestamp to each row . Let's see
131+ now an example with timestamps, custom auto-flushing, basic auth, and error
132132reporting.
133133
134134``` csharp
@@ -140,7 +140,9 @@ class Program
140140{
141141 static async Task Main (string [] args )
142142 {
143- using var sender = Sender .New (" http::addr=localhost:9000;username=admin;password=quest;auto_flush_rows=100;auto_flush_interval=1000;" );
143+ using var sender = Sender .New (
144+ " http::addr=localhost:9000;username=admin;password=quest;auto_flush_rows=100;auto_flush_interval=1000;"
145+ );
144146
145147 var now = DateTime .UtcNow ;
146148 try
@@ -171,81 +173,94 @@ class Program
171173}
172174```
173175
174- As you can see , both events use the same timestamp. We recommended using the
175- original event timestamps when ingesting data into QuestDB. Using the current
176- timestamp hinder the ability to deduplicate rows which is
176+ Now , both events use the same timestamp. We recommend using the event's
177+ original timestamp when ingesting data into QuestDB. Using ingestion-time
178+ timestamps precludes the ability to deduplicate rows, which is
177179[ important for exactly-once processing] ( /docs/reference/api/ilp/overview/#exactly-once-delivery-vs-at-least-once-delivery ) .
178180
179- ## Configuration
181+ ## Ways to create the client
180182
181- Construct new Senders via the ` Sender ` factory.
183+ There are three ways to create a client instance:
182184
183- It is mandatory to provide the ` addr ` config, as this defines the transport
184- protocol and the server location.
185+ 1 . ** From a configuration string.** This is the most common way to create a
186+ client instance. It describes the entire client configuration in a single
187+ string. See [ Configuration options] ( #configuration-options ) for all available
188+ options. It allows sharing the same configuration across clients in different
189+ languages.
185190
186- By default, the HTTP protocol uses ` 9000 ` , the same as the other HTTP endpoints.
187- Optionally, TCP uses ` 9009 ` .
191+ ``` csharp
192+ using var sender = Sender .New (" http::addr=localhost:9000;" );
193+ ```
188194
189- ### With a configuration string
195+ 2 . ** From an environment variable.** The ` QDB_CLIENT_CONF ` environment variable
196+ is used to set the configuration string. Moving configuration parameters to
197+ an environment variable allows you to avoid hard-coding sensitive information
198+ such as tokens and password in your code.
190199
191- It is recommended, where possible, to initialise the sender using a
192- [ configuration string] ( /docs/configuration-string/ ) .
200+ If you want to initialise some properties programmatically after the initial
201+ config string, you can use ` Configure ` and ` Build ` .
193202
194- Configuration strings provide a convenient shorthand for defining client
195- properties, and are validated during construction of the ` Sender ` .
203+ ``` bash
204+ export QDB_CLIENT_CONF=" http::addr=localhost:9000;auto_flush_rows=5000;retry_timeout=10000;"
205+ ```
196206
197- ``` csharp
198- using var sender = Sender .New (" http::addr=localhost:9000;" );
199- ```
207+ ``` csharp
208+ ( Sender .Configure (" http::addr=localhost:9000;" ) with { auto_flush = AutoFlushType . off }). Build ()
209+ ```
200210
201- If you want to initialise some properties programmatically after the initial
202- config string, you can use ` Configure ` and ` Build ` .
211+ 3 . ** From SenderOptions.**
203212
204- ``` csharp
205- ( Sender . Configure ( " http::addr=localhost:9000; " ) with { auto_flush = AutoFlushType . off }). Build ()
206- ```
213+ ``` csharp
214+ await using var sender = Sender . New ( new SenderOptions ());
215+ ```
207216
208- ### From options
217+ This way you can bind options from configuration:
209218
210- The sender API also supports construction from ` SenderOptions ` .
219+ ``` json
220+ {
221+ "QuestDB" : {
222+ "addr" : " localhost:9000" ,
223+ "tls_verify" : " unsafe_off;"
224+ }
225+ }
226+ ```
211227
212- ``` csharp
213- await using var sender = Sender .New (new SenderOptions ());
214- ```
228+ ``` csharp
229+ var options = new ConfigurationBuilder ()
230+ .AddJsonFile (" config.json" )
231+ .Build ()
232+ .GetSection (" QuestDB" )
233+ .Get <SenderOptions >();
234+ ```
215235
216- You might use this when binding options from configuration:
236+ ## Configuration options
217237
218- ``` json
219- {
220- "QuestDB" : {
221- "addr" : " localhost:9000" ,
222- "tls_verify" : " unsafe_off;"
223- }
224- }
238+ The easiest way to configure the ` Sender ` is the configuration string. The
239+ general structure is:
240+ ``` plain
241+ <transport>::addr=host:port;param1=val1;param2=val2;...
225242```
243+ ` transport ` can be ` http ` , ` https ` , ` tcp ` , or ` tcps ` . Go to the client's
244+ [ crate documentation] ( https://docs.rs/questdb-rs/latest/questdb/ingress ) for the
245+ full details on configuration.
246+ Alternatively, for breakdown of available params, see the
247+ [ Configuration string] ( /docs/configuration-string/ ) page.
226248
227- ``` csharp
228- var options = new ConfigurationBuilder ()
229- .AddJsonFile (" config.json" )
230- .Build ()
231- .GetSection (" QuestDB" )
232- .Get <SenderOptions >();
233- ```
234249
235250## Preparing Data
236251
237- Senders use an internal buffer to convert input values into an ILP-compatible
238- UTF-8 byte-string.
252+ The Sender uses an internal buffer to convert input values into an
253+ ILP-compatible UTF-8 byte-string.
239254
240- This buffer can be controlled using the ` init_buf_size ` and ` max_buf_size `
255+ You can control buffer sizing with the ` init_buf_size ` and ` max_buf_size `
241256parameters.
242257
243258Here is how to build a buffer of rows ready to be sent to QuestDB.
244259
245260::: warning
246261
247262The senders are ** not** thread safe, since they manage an internal buffer. If
248- you wish to send data in parallel, you should construct multiple senders and use
263+ you wish to send data in parallel, construct multiple senders and use
249264non-blocking I/O to submit to QuestDB.
250265
251266:::
@@ -281,44 +296,46 @@ The table name must always be called before other builder functions.
281296### Add symbols
282297
283298A [ symbol] ( /docs/concept/symbol/ ) is a dictionary-encoded string, used to
284- efficiently store commonly repeated data. This is frequently used for
285- identifiers, and symbol columns can have
286- [ secondary indexes ] ( /docs/concept/indexes/ ) defined upon them .
299+ efficiently store commonly repeated data. We recommend using this type for
300+ identifiers, because you can create a
301+ [ secondary index ] ( /docs/concept/indexes/ ) for a symbol column .
287302
288- Symbols can be added using calls to ` Symbol ` , which expects a symbol column
289- name, and string value.
303+ Add symbols by calling ` Symbol() ` , which expects a symbol column
304+ name, and a string value.
290305
291306``` csharp
292307sender .Symbol (" foo" , " bah" );
293308```
294309
295- All symbol columns must be defined before any other column definition .
310+ You must specify all symbol columns first, before any other columns .
296311
297312### Add other columns
298313
299- A number of data types can be submitted to QuestDB via ILP, including string /
314+ There are several data types you can send to QuestDB via ILP, including string /
300315long / double / DateTime / DateTimeOffset.
301316
302- These can be written using the ` Column ` functions .
317+ Provide these by calling ` Column() ` .
303318
304319``` csharp
305320sender .Column (" baz" , 102 );
306321```
307322
308323### Finish the row
309324
310- A row is completed by defining the designated timestamp value :
325+ Completed a row by specifying the designated timestamp:
311326
312327``` csharp
313328sender .At (DateTime .UtcNow );
314329```
315330
316- Generation of the timestamp can be offloaded to the server, using ` AtNow ` .
331+ You can also let the server assign the timestamp, by calling ` AtNow() ` instead .
317332
318333::: caution
319334
320- Using a server generated timestamp via AtNow/AtNowAsync is not compatible with
321- QuestDB's deduplication feature, and should be avoided where possible.
335+ We recommend using the event's original timestamp when ingesting data into
336+ QuestDB. Using ingestion-time timestamps precludes the ability to deduplicate
337+ rows, which is
338+ [ important for exactly-once processing] ( /docs/reference/api/ilp/overview/#exactly-once-delivery-vs-at-least-once-delivery ) .
322339
323340:::
324341
@@ -329,16 +346,15 @@ database automatically, or manually.
329346
330347### Auto-flushing
331348
332- When the ` At ` functions are called, the auto-flushing parameters are checked to
333- see if it is appropriate to flush the buffer. If an auto-flush is triggered,
334- data will be sent to QuestDB.
349+ When you call one of the ` At ` functions, the row is complete. The sender checks
350+ the auto-flushing parameters to see if it should flush the buffer to the server.
335351
336352``` csharp
337353sender .At (new DateTime (0 ,0 ,1 ));
338354```
339355
340- To avoid blocking the calling thread, one can use the Async overloads of the
341- ` At ` . functions e.g ` AtAsync ` .
356+ To avoid blocking the calling thread, use the Async overloads of the ` At ` , such
357+ as ` AtAsync ` .
342358
343359``` csharp
344360await sender .AtNowAsync ();
@@ -352,54 +368,52 @@ using var sender = Sender.New("http::addr=localhost:9000;auto_flush=off;"); // o
352368
353369#### Flush by rows
354370
355- Users can specify a threshold of rows to flush. This is effectively a submission
356- batch size by number of rows .
371+ You can specify the number of rows that will trigger an auto-flush, creating a
372+ batch insert operation of that size .
357373
358374``` csharp
359375using var sender = Sender .New (" http::addr=localhost:9000;auto_flush=on;auto_flush_rows=5000;" );
360376```
361377
362- By default, HTTP senders will send after ` 75,000 ` rows, and TCP after ` 600 `
378+ By default, the HTTP sender auto-flushes after 75,000 rows, and TCP after 600
363379rows.
364380
365381::: tip
366382
367383` auto_flush_rows ` and ` auto_flush_interval ` are both enabled by default. If you
368- wish to only auto-flush based on one of these properties, you can disable the
369- other using ` off ` or ` -1 ` .
384+ wish to only auto-flush based on one of these properties, disable the other
385+ using ` off ` or ` -1 ` .
370386
371387:::
372388
373389#### Flush by interval
374390
375- Specify a time interval between batches. This is the elapsed time from the last
376- flush, and is checked when the ` At ` functions are called .
391+ You can specify the time interval between auto-flushes. The sender checks it
392+ every time you call an ` At ` function .
377393
378394``` csharp
379395using var sender = Sender .New (" http::addr=localhost:9000;auto_flush=on;auto_flush_interval=5000;" );
380396```
381397
382- By default, ` auto_flush_interval ` is set to ` 1000 ` ms.
398+ By default, ` auto_flush_interval ` is 1000 ms.
383399
384400#### Flush by bytes
385401
386- Specify a buffer length after which to flush, effectively a batch size in UTF-8
387- bytes. This should be set according to ` init_buf_size ` $\lt$ ` auto_flush_bytes `
388- $\leq$ ` max_buf_size ` .
402+ As an additional option, disabled by default, you can specify the batch size in
403+ terms of bytes instead of rows. You should ensure that ` init_buf_size `
404+ $\lt$ ` auto_flush_bytes ` $\ leq$ ` max_buf_size ` .
389405
390- This can be useful if a user has variety in their row sizes and wants to limit
391- the request sizes.
406+ This can be useful if you have large variation in row sizes and want to limit
407+ the request sizes. By default, this is disabled, but set to ` 100 KiB ` .
392408
393409``` csharp
394410using var sender = Sender .New (" http::addr=localhost:9000;auto_flush=on;auto_flush_bytes=65536;" );
395411```
396412
397- By default, this is disabled, but set to ` 100 KiB ` .
398-
399413### Explicit flushing
400414
401- Manually flush the buffer using ` Send ` . and ` SendAsync ` . This will send any
402- outstanding data to the QuestDB server.
415+ You can also manually flush the buffer at any time by calling ` Send ` or
416+ ` SendAsync ` . This will send any outstanding data to the QuestDB server.
403417
404418``` csharp
405419using var sender = Sender .New (" http::addr=localhost:9000;auto_flush=off;" );
@@ -409,8 +423,10 @@ await sender.SendAsync(); // send non-blocking
409423sender .Send (); // send synchronously
410424```
411425
412- It is recommended to always end your submission code with a manual flush. This
413- will ensure that all data has been sent before disposing of the Sender.
426+ You should always perform an explicit flush before closing the sender. The HTTP
427+ sender normally retries the requests in case of errors, but won't do that while
428+ auto-flushing before closing. Flushing explicitly ensures that the client
429+ applies the same effort to send all the remaining data.
414430
415431## Transactions
416432
@@ -478,7 +494,8 @@ Add data to a transaction in the usual way, but without calling `Table` between
478494rows.
479495
480496``` csharp
481- sender .Symbol (" bah" , " baz" ).Column (" num" , 123 ).At (DateTime .UtcNow ); // adds a symbol, integer column, and ends with current timestamp
497+ // add a symbol, integer column, and end with current timestamp
498+ sender .Symbol (" bah" , " baz" ).Column (" num" , 123 ).At (DateTime .UtcNow );
482499```
483500
484501### Closing a transaction
@@ -498,7 +515,7 @@ server.
498515sender .Rollback ();
499516```
500517
501- ## Misc.
518+ ## Misc
502519
503520### Cancelling rows
504521
@@ -581,7 +598,6 @@ using var sender =
581598 Sender .New (
582599 " tcps::addr=localhost:9009;tls_verify=unsafe_off;username=admin;token=NgdiOWDoQNUP18WOnb1xkkEG5TzPYMda5SiUOvT1K0U=;" );
583600// See: /docs/reference/api/ilp/authenticate
584-
585601```
586602
587603## Next Steps
0 commit comments