camusdb 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +250 -0
- package/dist/client.d.ts +73 -39
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +158 -169
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +22 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +19 -0
- package/dist/config.js.map +1 -1
- package/dist/endpoint-pool.d.ts +8 -0
- package/dist/endpoint-pool.d.ts.map +1 -1
- package/dist/endpoint-pool.js +25 -0
- package/dist/endpoint-pool.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/node-stats.d.ts +113 -0
- package/dist/node-stats.d.ts.map +1 -0
- package/dist/node-stats.js +90 -0
- package/dist/node-stats.js.map +1 -0
- package/dist/options.d.ts +10 -0
- package/dist/options.d.ts.map +1 -1
- package/dist/options.js +1 -0
- package/dist/options.js.map +1 -1
- package/dist/pipeline.d.ts +136 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +375 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/prepared/auto-prepare.d.ts +51 -0
- package/dist/prepared/auto-prepare.d.ts.map +1 -0
- package/dist/prepared/auto-prepare.js +150 -0
- package/dist/prepared/auto-prepare.js.map +1 -0
- package/dist/prepared/policy.d.ts +7 -0
- package/dist/prepared/policy.d.ts.map +1 -1
- package/dist/prepared/policy.js +16 -0
- package/dist/prepared/policy.js.map +1 -1
- package/dist/query-stream.d.ts +9 -1
- package/dist/query-stream.d.ts.map +1 -1
- package/dist/query-stream.js +20 -2
- package/dist/query-stream.js.map +1 -1
- package/dist/retry.d.ts +8 -0
- package/dist/retry.d.ts.map +1 -1
- package/dist/retry.js +12 -1
- package/dist/retry.js.map +1 -1
- package/dist/sql-syntax.d.ts +6 -0
- package/dist/sql-syntax.d.ts.map +1 -1
- package/dist/sql-syntax.js +8 -0
- package/dist/sql-syntax.js.map +1 -1
- package/dist/statements.d.ts +14 -0
- package/dist/statements.d.ts.map +1 -1
- package/dist/statements.js +45 -3
- package/dist/statements.js.map +1 -1
- package/dist/telemetry.d.ts +199 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +423 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/transaction.d.ts +60 -5
- package/dist/transaction.d.ts.map +1 -1
- package/dist/transaction.js +124 -24
- package/dist/transaction.js.map +1 -1
- package/dist/transport/authenticating-transport.d.ts +9 -1
- package/dist/transport/authenticating-transport.d.ts.map +1 -1
- package/dist/transport/authenticating-transport.js +13 -0
- package/dist/transport/authenticating-transport.js.map +1 -1
- package/dist/transport/grpc/batch-frames.d.ts +23 -5
- package/dist/transport/grpc/batch-frames.d.ts.map +1 -1
- package/dist/transport/grpc/batch-frames.js +29 -8
- package/dist/transport/grpc/batch-frames.js.map +1 -1
- package/dist/transport/grpc/batcher.d.ts +69 -5
- package/dist/transport/grpc/batcher.d.ts.map +1 -1
- package/dist/transport/grpc/batcher.js +217 -10
- package/dist/transport/grpc/batcher.js.map +1 -1
- package/dist/transport/grpc/grpc-transport.d.ts +35 -1
- package/dist/transport/grpc/grpc-transport.d.ts.map +1 -1
- package/dist/transport/grpc/grpc-transport.js +193 -7
- package/dist/transport/grpc/grpc-transport.js.map +1 -1
- package/dist/transport/grpc/messages.d.ts +15 -0
- package/dist/transport/grpc/messages.d.ts.map +1 -1
- package/dist/transport/grpc/messages.js +9 -0
- package/dist/transport/grpc/messages.js.map +1 -1
- package/dist/transport/rest-transport.d.ts +9 -1
- package/dist/transport/rest-transport.d.ts.map +1 -1
- package/dist/transport/rest-transport.js +24 -0
- package/dist/transport/rest-transport.js.map +1 -1
- package/dist/transport/sequential-pipeline.d.ts +21 -0
- package/dist/transport/sequential-pipeline.d.ts.map +1 -0
- package/dist/transport/sequential-pipeline.js +119 -0
- package/dist/transport/sequential-pipeline.js.map +1 -0
- package/dist/transport/transport.d.ts +94 -0
- package/dist/transport/transport.d.ts.map +1 -1
- package/dist/transport/transport.js +10 -0
- package/dist/transport/transport.js.map +1 -1
- package/package.json +10 -4
- package/proto/camus_sql.proto +114 -0
package/README.md
CHANGED
|
@@ -12,6 +12,9 @@ The gRPC transport needs two more packages. Install them only if you use it:
|
|
|
12
12
|
npm install @grpc/grpc-js @grpc/proto-loader
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
Traces and metrics need `@opentelemetry/api`. Install it only if you collect them. See
|
|
16
|
+
[OpenTelemetry](#opentelemetry).
|
|
17
|
+
|
|
15
18
|
**Requirements**: Node.js 20.19 or later, or 22.12 or later. The package ships as ECMAScript
|
|
16
19
|
modules with TypeScript declarations.
|
|
17
20
|
|
|
@@ -36,8 +39,10 @@ modules with TypeScript declarations.
|
|
|
36
39
|
- [Databases and branches](#databases-and-branches)
|
|
37
40
|
- [The query result cache](#the-query-result-cache)
|
|
38
41
|
- [Backups](#backups)
|
|
42
|
+
- [Node stats](#node-stats)
|
|
39
43
|
- [Errors](#errors)
|
|
40
44
|
- [Cancellation and deadlines](#cancellation-and-deadlines)
|
|
45
|
+
- [OpenTelemetry](#opentelemetry)
|
|
41
46
|
- [What a client shares](#what-a-client-shares)
|
|
42
47
|
- [Security notes](#security-notes)
|
|
43
48
|
- [Development](#development)
|
|
@@ -119,6 +124,7 @@ const b = CamusClient.fromConnectionString('Endpoint=http://localhost:8082;Datab
|
|
|
119
124
|
| `coalescingDelayMs` | `CoalescingDelay` | No | gRPC only: milliseconds. Default `0`, which is off. |
|
|
120
125
|
| `requestFrames` | `RequestFrames` | No | gRPC only: pack the operations that wait together into one stream message. Default `true`. |
|
|
121
126
|
| `streamDrainTimeoutMs` | `StreamDrainTimeout` | No | gRPC only: milliseconds a rotated-out stream stays open for its transactions. Default `300000`. |
|
|
127
|
+
| `httpVersion` | `HttpVersion` | No | The highest HTTP version for REST calls. Only `1.1` (the default) is accepted. See the note below. |
|
|
122
128
|
| `backupEndpoint` | `BackupEndpoint` | No | The HTTP endpoint for the backup admin API. Required with `grpc`. |
|
|
123
129
|
| `backupTimeoutSeconds` | `BackupTimeout` | No | The backup request timeout in seconds. Default `300`. |
|
|
124
130
|
| `allowInsecureCredentials` | `AllowInsecureCredentials` | No | Waives the refusal to send credentials to a remote plaintext endpoint. |
|
|
@@ -127,6 +133,13 @@ const b = CamusClient.fromConnectionString('Endpoint=http://localhost:8082;Datab
|
|
|
127
133
|
| `routingMaxHintAgeMs` | `RoutingMaxHintAge` | No | The ceiling on how long a learned route is reused. Default `5000`. |
|
|
128
134
|
| `defaultTransactionOptions` | `IsolationLevel`, `TransactionMode`, `Locking` | No | Concurrency defaults for every transaction and autocommit statement. |
|
|
129
135
|
| `int64` | `Int64` | No | `auto` (the default), `number`, or `bigint`. See [Types](#types). |
|
|
136
|
+
| `traceQueryText` | `TraceQueryText` | No | Put the SQL text on the driver's spans as `db.query.text`. Default `false`. See [OpenTelemetry](#opentelemetry). |
|
|
137
|
+
|
|
138
|
+
**`HttpVersion`.** The .NET driver reads `HttpVersion=1.1|2|3` and can send REST calls over HTTP/2
|
|
139
|
+
or HTTP/3. Node's `fetch` sends HTTP/1.1 only. So this driver accepts `1.1`, and it refuses `2` and
|
|
140
|
+
`3` (also `2.0` and `3.0`) with a `CamusError` when the client is built. Remove the key, or set it
|
|
141
|
+
to `1.1`, in a connection string that you share with a .NET service. Any other value reads as `1.1`,
|
|
142
|
+
as in .NET. The key does not apply to `protocol: 'grpc'`, which always uses HTTP/2.
|
|
130
143
|
|
|
131
144
|
### How a connection string is parsed
|
|
132
145
|
|
|
@@ -601,6 +614,63 @@ same transaction, `SELECT currval('…')` returns the value again. The server ac
|
|
|
601
614
|
where it can count the values before the statement runs, so a `nextval` in a derived table fails
|
|
602
615
|
with `CADB0547`.
|
|
603
616
|
|
|
617
|
+
### C# extensions: procedures, triggers, and functions
|
|
618
|
+
|
|
619
|
+
The server can run C# code from an extension assembly as stored procedures, row triggers, and scalar
|
|
620
|
+
functions. The operator deploys the assembly and lists it in the server configuration. The driver
|
|
621
|
+
needs no setup.
|
|
622
|
+
|
|
623
|
+
Run a procedure with `CALL`. A procedure returns no result set. `execute` reports the number of rows
|
|
624
|
+
that the procedure's SQL changed:
|
|
625
|
+
|
|
626
|
+
```ts
|
|
627
|
+
const { affectedRows } = await client.execute('CALL transfer(@from, @to, @amount)', {
|
|
628
|
+
from: 'alice',
|
|
629
|
+
to: 'bob',
|
|
630
|
+
amount: 30,
|
|
631
|
+
});
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
`call` takes the procedure name only. It sends `CALL name(@a, @b, ...)` with the parameters in the
|
|
635
|
+
order of the object's keys, because a procedure takes its arguments by position:
|
|
636
|
+
|
|
637
|
+
```ts
|
|
638
|
+
await client.call('transfer', { from: 'alice', to: 'bob', amount: 30 });
|
|
639
|
+
// runs CALL transfer(@from, @to, @amount)
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
- The procedure name must be a plain identifier: a letter or `_`, then letters, digits, or `_`. Any
|
|
643
|
+
other text throws `TypeError` before the driver sends the call.
|
|
644
|
+
- JavaScript puts a key that is a whole number, such as `'0'`, before the other keys. So give the
|
|
645
|
+
parameters names.
|
|
646
|
+
- Only input parameters are supported. A procedure has no output parameters and no return value.
|
|
647
|
+
- `query`, `queryOne`, `scalar`, and `queryStream` also send `CALL` to the non-query route. The
|
|
648
|
+
result has no rows, and `affectedRows` is the changed-row count. On a stream, `affectedRows` is
|
|
649
|
+
`undefined` for a query.
|
|
650
|
+
- A pipeline accepts `CALL` through `query`, `execute`, and `call`.
|
|
651
|
+
- `CALL` is not prepared. It runs inside the `transaction` option, if there is one, and an error
|
|
652
|
+
rolls back everything that the procedure wrote.
|
|
653
|
+
- `CALL` needs a superuser in this server version.
|
|
654
|
+
|
|
655
|
+
`CREATE TRIGGER` and `DROP TRIGGER` go to the DDL route, as other schema statements do:
|
|
656
|
+
|
|
657
|
+
```ts
|
|
658
|
+
await client.execute(
|
|
659
|
+
"CREATE TRIGGER audit ON orders AFTER INSERT, UPDATE, DELETE EXTERNAL NAME 'MyCompany.Ext.AuditTrigger'",
|
|
660
|
+
);
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
An extension function is called in SQL like a built-in function, for example
|
|
664
|
+
`SELECT slugify(title) FROM posts`. `SHOW EXTENSIONS` lists the assemblies that a node loaded. It
|
|
665
|
+
needs a superuser.
|
|
666
|
+
|
|
667
|
+
The server reports extension errors with `CADB08xx` codes in `CamusError.code`. For example,
|
|
668
|
+
`CADB0822` means that a procedure threw, and `CADB0818` means that a trigger threw. `CADB0817` means
|
|
669
|
+
that this node does not load the trigger's extension, or loads another build of it. The driver does
|
|
670
|
+
not retry `CADB0817`, because the cause is the deployment, not a conflict. The server can run a
|
|
671
|
+
statement again after a serializable conflict, so a trigger or a procedure can run more than once.
|
|
672
|
+
See `docs/csharp-extensions.md` in the server repository for the full rules.
|
|
673
|
+
|
|
604
674
|
---
|
|
605
675
|
|
|
606
676
|
## Streaming
|
|
@@ -693,6 +763,10 @@ await client.transaction(work, {
|
|
|
693
763
|
- **`locking`** — `Pessimistic` (the default) takes locks up front. `Optimistic` stages the writes
|
|
694
764
|
and detects a conflict only at commit; a losing transaction fails its commit and must be retried.
|
|
695
765
|
It does not protect against phantoms.
|
|
766
|
+
- **`deferBegin`** — `true` sends `BEGIN` with the first statement, and not from
|
|
767
|
+
`beginTransaction`. When that first statement is a pipeline send, `BEGIN` travels inside the same
|
|
768
|
+
exchange. With learned routing on, `BEGIN` is deferred already. The transaction identity reads as
|
|
769
|
+
zero until the first statement, and a failure to begin comes from that statement.
|
|
696
770
|
|
|
697
771
|
Every knob is optional. A knob left unset falls back to the client's `defaultTransactionOptions`,
|
|
698
772
|
then to the connection-string defaults, then to the server default.
|
|
@@ -706,6 +780,63 @@ dead, so the driver re-issues the **same** commit on the **same** handle, backin
|
|
|
706
780
|
times. It never replays the work from the start, because that could apply an already-durable commit
|
|
707
781
|
a second time. This is handled inside the driver; you do not write it.
|
|
708
782
|
|
|
783
|
+
### Pipelined transactions
|
|
784
|
+
|
|
785
|
+
A transaction that awaits each statement pays one round trip for each statement: six for a bank
|
|
786
|
+
transfer (`BEGIN`, two reads, two writes, `COMMIT`). At high concurrency, those round trips set the
|
|
787
|
+
latency, and the statements do not. A pipeline sends the statements whose inputs are known as one
|
|
788
|
+
stream message, and it settles the promise of each statement from its own answer.
|
|
789
|
+
|
|
790
|
+
```ts
|
|
791
|
+
const txn = await client.beginTransaction({
|
|
792
|
+
locking: CamusLocking.Optimistic,
|
|
793
|
+
deferBegin: true, // BEGIN travels inside the first send
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
const pipeline = txn.pipeline();
|
|
797
|
+
|
|
798
|
+
// Exchange 1: [BEGIN, SELECT a, SELECT b]
|
|
799
|
+
const readA = pipeline.query<{ balance: number }>('SELECT balance FROM accounts WHERE id = @id', { id: a });
|
|
800
|
+
const readB = pipeline.query<{ balance: number }>('SELECT balance FROM accounts WHERE id = @id', { id: b });
|
|
801
|
+
await pipeline.send();
|
|
802
|
+
|
|
803
|
+
const fromBalance = (await readA).rows[0]!.balance;
|
|
804
|
+
const toBalance = (await readB).rows[0]!.balance;
|
|
805
|
+
|
|
806
|
+
// Exchange 2: [UPDATE a, UPDATE b, COMMIT]. The commit happens only if both updates succeed.
|
|
807
|
+
pipeline.execute('UPDATE accounts SET balance = @v WHERE id = @id', { v: fromBalance - amount, id: a });
|
|
808
|
+
pipeline.execute('UPDATE accounts SET balance = @v WHERE id = @id', { v: toBalance + amount, id: b });
|
|
809
|
+
await pipeline.commit();
|
|
810
|
+
|
|
811
|
+
console.log(`${pipeline.exchanges} round trips`); // 2 over gRPC
|
|
812
|
+
```
|
|
813
|
+
|
|
814
|
+
- **Results.** `query` returns the promise of a `QueryResult`, and `execute` returns the promise of
|
|
815
|
+
an `ExecuteResult`, as the client methods do. A write with `RETURNING` in `query` gives its rows
|
|
816
|
+
and `affectedRows`. `send` and `commit` also reject with the first failure, so a caller that awaits
|
|
817
|
+
only the send still learns of it. A queued promise that nobody awaits is never reported as an
|
|
818
|
+
unhandled rejection.
|
|
819
|
+
- **Failure.** The statements after a failed one in the same exchange still get an answer. The
|
|
820
|
+
transaction has ended, so they fail too, and `commit` rejects with the first failure and does not
|
|
821
|
+
commit. The server rolled the transaction back, so `rollback` is then a harmless call. To retry,
|
|
822
|
+
run the whole transaction again from `BEGIN`, as for any failed statement.
|
|
823
|
+
- **Commit.** After a successful `pipeline.commit()`, the transaction is committed. A later
|
|
824
|
+
`txn.rollback()` does nothing, and a later `txn.commit()` throws. Inside `client.transaction`, the
|
|
825
|
+
helper sees the pipeline commit and does not commit a second time.
|
|
826
|
+
- **Order.** The queued statements run in queue order, after every statement of the transaction
|
|
827
|
+
sent before them. A pipeline can be sent more than once on one transaction, and an ordinary
|
|
828
|
+
statement can run between two sends. One send at a time for each pipeline.
|
|
829
|
+
- **Exchanges.** `pipeline.exchanges` gives the round trips used. Over gRPC, to a server that
|
|
830
|
+
announces frame contract version 2 or higher, it is one for each send. Over REST, with
|
|
831
|
+
`requestFrames: false`, or against an older server, the driver runs the same statements one
|
|
832
|
+
exchange per step, with the same results, and the count shows it. The driver never sends an
|
|
833
|
+
older server something that it could misread.
|
|
834
|
+
- **Routing.** With learned routing on, a pipelined statement asks for routing advice, and the
|
|
835
|
+
driver learns the route from its reply, as for a lone statement. So the next deferred transaction
|
|
836
|
+
begins on the node that the advice names.
|
|
837
|
+
- **What cannot be queued.** DDL, which does not run inside the transaction, and `TRUNCATE`. These
|
|
838
|
+
throw a `CamusError` at queue time, and the pipeline stays usable.
|
|
839
|
+
|
|
709
840
|
---
|
|
710
841
|
|
|
711
842
|
## Retries
|
|
@@ -845,6 +976,10 @@ frame, and the fixed cost of a message is paid once instead of six times. A fram
|
|
|
845
976
|
more statements. A lone statement stays a plain single message, and a server that does not announce
|
|
846
977
|
frames never receives one. Set `requestFrames` to `false` to turn frames off.
|
|
847
978
|
|
|
979
|
+
A whole transaction can travel as one frame too: a pipeline puts the `BEGIN`, the statements, and a
|
|
980
|
+
conditional commit in one stream message. That needs a server that announces frame contract version
|
|
981
|
+
2. See [Pipelined transactions](#pipelined-transactions).
|
|
982
|
+
|
|
848
983
|
A stream carries its bearer token once, in the metadata it opens with, and gRPC gives no way to
|
|
849
984
|
change it later. The token provider renews the token every few minutes, so a long-lived stream
|
|
850
985
|
outlives the token it presented. Whether a server tolerates that is the server's decision. The
|
|
@@ -1066,6 +1201,39 @@ HTTP endpoint; the driver refuses to guess rather than send HTTP at a gRPC port.
|
|
|
1066
1201
|
|
|
1067
1202
|
---
|
|
1068
1203
|
|
|
1204
|
+
## Node stats
|
|
1205
|
+
|
|
1206
|
+
`client.nodeStats()` returns the disk, CPU, and memory of one node. It works over REST
|
|
1207
|
+
(`GET /v1/admin/stats`) and gRPC (`GetNodeStats`).
|
|
1208
|
+
|
|
1209
|
+
```ts
|
|
1210
|
+
const stats = await client.nodeStats(); // the next endpoint in the rotation
|
|
1211
|
+
const data = stats.dataVolume!; // the volume that holds data_dir
|
|
1212
|
+
|
|
1213
|
+
console.log(`${data.availableBytes} bytes free of ${data.totalBytes}`);
|
|
1214
|
+
console.log(`writes refused (below min_free_disk_bytes): ${data.belowWatermark}`);
|
|
1215
|
+
|
|
1216
|
+
for (const endpoint of client.endpoints) {
|
|
1217
|
+
const node = await client.nodeStats(endpoint); // one call for each node of a cluster
|
|
1218
|
+
console.log(`${node.address}: ${node.cpu.processCpuPercent}% CPU, ${node.memory.hostAvailableBytes} bytes free`);
|
|
1219
|
+
}
|
|
1220
|
+
```
|
|
1221
|
+
|
|
1222
|
+
- **Each node answers for itself.** `address` names the configured endpoint that answered.
|
|
1223
|
+
`nodeStats(endpoint)` accepts only an endpoint from `client.endpoints`, so the client's credentials
|
|
1224
|
+
never go to another address. Any other endpoint throws a `TypeError`.
|
|
1225
|
+
- **`-1` means unknown.** A value that the node could not read is `-1`, and `errors` names the field
|
|
1226
|
+
and the reason. One failed probe never fails the call. A value that an older server does not send
|
|
1227
|
+
is `-1` too.
|
|
1228
|
+
- **`belowWatermark` is the answer of the write gate.** While it is `true`, writes on that node fail
|
|
1229
|
+
with `CADB0536`.
|
|
1230
|
+
- **`MONITOR`, not superuser.** With authentication on, the account needs the superuser attribute or
|
|
1231
|
+
the `MONITOR` privilege: `GRANT MONITOR ON *.* TO monitoring;`. Other accounts get `CADB0517`.
|
|
1232
|
+
- **Cheap enough to poll.** The server answers from caches and a background sampler, so one call
|
|
1233
|
+
each minute from several monitors costs nothing measurable.
|
|
1234
|
+
|
|
1235
|
+
---
|
|
1236
|
+
|
|
1069
1237
|
## Errors
|
|
1070
1238
|
|
|
1071
1239
|
Every database-level failure is a `CamusError` carrying the server's `CADBxxxx` code.
|
|
@@ -1117,6 +1285,88 @@ not marked unreachable.
|
|
|
1117
1285
|
|
|
1118
1286
|
---
|
|
1119
1287
|
|
|
1288
|
+
## OpenTelemetry
|
|
1289
|
+
|
|
1290
|
+
The driver reports traces and metrics through `@opentelemetry/api`, which is an optional peer
|
|
1291
|
+
dependency. Install it, and register an OpenTelemetry SDK as usual. The driver needs no plugin and
|
|
1292
|
+
no extra setting:
|
|
1293
|
+
|
|
1294
|
+
```shell
|
|
1295
|
+
npm install @opentelemetry/api @opentelemetry/sdk-node
|
|
1296
|
+
```
|
|
1297
|
+
|
|
1298
|
+
```ts
|
|
1299
|
+
import { NodeSDK } from '@opentelemetry/sdk-node';
|
|
1300
|
+
|
|
1301
|
+
new NodeSDK({ /* exporters */ }).start();
|
|
1302
|
+
|
|
1303
|
+
// Every client reports from now on, under the instrumentation scope 'camusdb' (CAMUS_TELEMETRY_NAME).
|
|
1304
|
+
```
|
|
1305
|
+
|
|
1306
|
+
Without the package, the driver reports nothing and loads nothing for telemetry. The driver loads
|
|
1307
|
+
the package with `require` on the first operation, so the first operation is reported too. Register
|
|
1308
|
+
the SDK before the first database call.
|
|
1309
|
+
|
|
1310
|
+
**Spans.** The driver records one client span for each of these operations:
|
|
1311
|
+
|
|
1312
|
+
- A statement: `query` (and so `queryOne`, `scalar`, and `nextSequenceValue`), `queryStream`,
|
|
1313
|
+
`execute`, `executeDdl`, `evictCache`, and `evictAllCache`.
|
|
1314
|
+
- A typed insert (`insert`).
|
|
1315
|
+
- `BEGIN`, `COMMIT`, and `ROLLBACK`. One `COMMIT` span covers all the retries of an unresolved
|
|
1316
|
+
commit (`CADB0509`), with one `camusdb.retry` event for each retry.
|
|
1317
|
+
- A pipeline exchange, as one `BATCH` span with `db.operation.batch.size` and
|
|
1318
|
+
`camusdb.pipeline.commit`.
|
|
1319
|
+
|
|
1320
|
+
The span name is `{operation} {target}`, for example `SELECT shop`. The target is the table for a
|
|
1321
|
+
typed insert, and the database for all other operations. The span has these attributes from the
|
|
1322
|
+
[OpenTelemetry database conventions](https://opentelemetry.io/docs/specs/semconv/database/):
|
|
1323
|
+
|
|
1324
|
+
| Attribute | Value |
|
|
1325
|
+
| --- | --- |
|
|
1326
|
+
| `db.system.name` | `camusdb` |
|
|
1327
|
+
| `db.namespace` | The database of the client. |
|
|
1328
|
+
| `db.operation.name` | The first keyword of the SQL text, if it is a known verb (`SELECT`, `INSERT`, `UPDATE`, `DELETE`, `CREATE`, `ALTER`, `DROP`, `TRUNCATE`, and others), or `BEGIN`, `COMMIT`, `ROLLBACK`, `BATCH`. |
|
|
1329
|
+
| `db.collection.name` | The table of a typed insert. |
|
|
1330
|
+
| `server.address`, `server.port` | The endpoint that received the operation, after routing. |
|
|
1331
|
+
| `db.query.text` | The SQL text. Only with `traceQueryText: true`. |
|
|
1332
|
+
| `error.type`, `db.response.status_code` | The `CADBxxxx` code of a failed operation, or the error name when there is no code. |
|
|
1333
|
+
| `camusdb.transport` | `rest` or `grpc`. |
|
|
1334
|
+
|
|
1335
|
+
The span is a child of the active span. While the operation runs, the driver span is the active
|
|
1336
|
+
span, so the HTTP or gRPC spans of the transport are its children. This needs a context manager,
|
|
1337
|
+
which `NodeSDK` registers.
|
|
1338
|
+
|
|
1339
|
+
**Duration metric.** The driver records the `db.client.operation.duration` histogram, in seconds,
|
|
1340
|
+
for the same operations. Its attributes are `db.system.name`, `db.namespace`, `db.operation.name`,
|
|
1341
|
+
`server.address`, `server.port`, `error.type`, and `db.response.status_code`. The SQL text is never
|
|
1342
|
+
an attribute.
|
|
1343
|
+
|
|
1344
|
+
**Driver metrics.** The same meter also has these metrics:
|
|
1345
|
+
|
|
1346
|
+
| Metric | Type | Attributes | What it counts |
|
|
1347
|
+
| --- | --- | --- | --- |
|
|
1348
|
+
| `camusdb.client.operation.retries` | Counter | `camusdb.retry.kind`, `error.type`, and `db.namespace` and `db.operation.name` when known | Each time the driver sends an operation again. The kinds are `finalize` (a `COMMIT` or `ROLLBACK` after `CADB0509`), `autocommit` (`withRetry`), `transaction` (`client.transaction` from `BEGIN`), `token_renewal` (a call sent again with a new token after `CADB0516`), and `create_database`. When a driver span is active, the retry is also a `camusdb.retry` event on it. |
|
|
1349
|
+
| `camusdb.client.endpoint.quarantines` | Counter | `server.address`, `server.port` | Each time an endpoint fails at the transport level and the driver sets it aside for 30 seconds. |
|
|
1350
|
+
| `camusdb.client.endpoint.quarantined` | Gauge | `server.address`, `server.port` | `1` while the endpoint is set aside, `0` while it takes traffic. |
|
|
1351
|
+
| `camusdb.client.prepared_statement.lookups` | Counter | `db.namespace`, `camusdb.prepared_statement.result` | Each execution of a preparable statement: `hit` (already prepared), `registered` (prepared by this execution), or `miss` (sent as SQL text). |
|
|
1352
|
+
| `camusdb.client.prepared_statement.registrations` | Counter | `db.namespace`, `camusdb.prepared_statement.result`, `error.type` | Each request to prepare a statement that got an answer: `success`, `refused` (the statement runs as SQL text from then on), or `unsupported` (the server has no prepared statements, so automatic preparation stops). |
|
|
1353
|
+
| `camusdb.client.prepared_statement.evictions` | Counter | `db.namespace` | Each prepared statement released to make room for one used more recently. See `maxAutoPrepare`. |
|
|
1354
|
+
| `camusdb.client.prepared_statement.count` | UpDownCounter | `db.namespace` | The statements kept prepared now. |
|
|
1355
|
+
|
|
1356
|
+
If `count` stays at `maxAutoPrepare` and `evictions` keeps growing, `maxAutoPrepare` is too small
|
|
1357
|
+
for the workload.
|
|
1358
|
+
|
|
1359
|
+
- **The SQL text is opt-in.** SQL text with literal values can contain sensitive data, so set
|
|
1360
|
+
`traceQueryText: true` (or `TraceQueryText=true`) to record it. The driver never records
|
|
1361
|
+
parameter values.
|
|
1362
|
+
- **A stream ends its span at the last row.** For `queryStream`, the span ends when the iteration
|
|
1363
|
+
reaches the last row, when a read fails, or when the stream is closed.
|
|
1364
|
+
- **A provider registered later.** The metrics API has no proxy provider, so the driver makes its
|
|
1365
|
+
instruments again when the global meter provider changes. Spans go through the proxy tracer of the
|
|
1366
|
+
API, so a tracer provider registered later gets them too.
|
|
1367
|
+
|
|
1368
|
+
---
|
|
1369
|
+
|
|
1120
1370
|
## What a client shares
|
|
1121
1371
|
|
|
1122
1372
|
A client holds no socket of its own. Four kinds of state are shared process-wide, keyed by what
|
package/dist/client.d.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { CamusBackupClient } from './backup.js';
|
|
8
8
|
import type { CamusCacheMetadata } from './cache.js';
|
|
9
9
|
import type { CamusClientOptions, CamusProtocol, ResolvedConfig } from './config.js';
|
|
10
|
+
import type { CamusNodeStats } from './node-stats.js';
|
|
10
11
|
import type { CamusTransactionOptions } from './options.js';
|
|
11
12
|
import { CamusQueryStream } from './query-stream.js';
|
|
12
13
|
import type { CamusColumn } from './result-set.js';
|
|
@@ -169,8 +170,12 @@ export declare class CamusClient implements AsyncDisposable {
|
|
|
169
170
|
* All the `RETURNING` rows arrive in one reply. On gRPC the server refuses a reply larger than
|
|
170
171
|
* 4 MiB with `CADB0550`, before the commit, so the statement stores nothing. Use `queryStream` for
|
|
171
172
|
* a large result, such as an `INSERT … SELECT … RETURNING` or an `UPDATE` of many rows.
|
|
173
|
+
*
|
|
174
|
+
* A `CALL` goes to the non-query route, because the server runs a procedure only there. The
|
|
175
|
+
* result has no rows, and `affectedRows` is the number of rows that the procedure's SQL changed.
|
|
172
176
|
*/
|
|
173
177
|
query<T = Record<string, unknown>>(sql: string, parameters?: Parameters, options?: AutocommitStatementOptions): Promise<QueryResult<T>>;
|
|
178
|
+
private runQuery;
|
|
174
179
|
/**
|
|
175
180
|
* Runs a `SELECT` and reads its first row, or `undefined` when it returned none. It accepts an
|
|
176
181
|
* `INSERT`, `UPDATE`, or `DELETE` with `RETURNING` as `query` does.
|
|
@@ -218,8 +223,13 @@ export declare class CamusClient implements AsyncDisposable {
|
|
|
218
223
|
* the same streaming query endpoint. Use this method for a `RETURNING` result that is too large
|
|
219
224
|
* for `query`. The server sends no row before the commit, so a conflict never surfaces mid-read
|
|
220
225
|
* for it. The stream reports no written-row count, so count the rows as you read them.
|
|
226
|
+
*
|
|
227
|
+
* A `CALL` goes to the non-query route, because the server runs a procedure only there. The
|
|
228
|
+
* procedure runs before this returns. The stream has no rows, and `affectedRows` is the number of
|
|
229
|
+
* rows that the procedure's SQL changed.
|
|
221
230
|
*/
|
|
222
231
|
queryStream<T = Record<string, unknown>>(sql: string, parameters?: Parameters, options?: AutocommitStatementOptions): Promise<CamusQueryStream<T>>;
|
|
232
|
+
private openQueryStream;
|
|
223
233
|
/**
|
|
224
234
|
* Runs an `INSERT`, `UPDATE`, or `DELETE` and reports how many rows it changed.
|
|
225
235
|
*
|
|
@@ -237,6 +247,25 @@ export declare class CamusClient implements AsyncDisposable {
|
|
|
237
247
|
* To read the rows, use `query`, `queryOne`, `scalar`, or `queryStream`.
|
|
238
248
|
*/
|
|
239
249
|
execute(sql: string, parameters?: Parameters, options?: AutocommitStatementOptions): Promise<ExecuteResult>;
|
|
250
|
+
/**
|
|
251
|
+
* Runs a procedure that a C# extension on the server defines, and reports how many rows the
|
|
252
|
+
* procedure's SQL changed.
|
|
253
|
+
*
|
|
254
|
+
* ```ts
|
|
255
|
+
* const { affectedRows } = await client.call('transfer', { from: 'alice', to: 'bob', amount: 30 });
|
|
256
|
+
* // runs CALL transfer(@from, @to, @amount)
|
|
257
|
+
* ```
|
|
258
|
+
*
|
|
259
|
+
* It sends `CALL procedure(@a, @b, ...)` with the parameters in the order of the object's keys,
|
|
260
|
+
* because a procedure takes its arguments by position. A procedure has no output parameters and
|
|
261
|
+
* no return value. The same statement as text also runs through `execute`, `query`, and
|
|
262
|
+
* `queryStream`. A `CALL` is not prepared, and it runs inside `options.transaction` when one is
|
|
263
|
+
* given.
|
|
264
|
+
*
|
|
265
|
+
* @throws {TypeError} when `procedure` is not a plain identifier: a letter or `_`, then letters,
|
|
266
|
+
* digits, or `_`. The driver sends nothing.
|
|
267
|
+
*/
|
|
268
|
+
call(procedure: string, parameters?: Parameters, options?: AutocommitStatementOptions): Promise<ExecuteResult>;
|
|
240
269
|
/**
|
|
241
270
|
* Runs a schema statement: `CREATE TABLE`, `ALTER TABLE`, `DROP INDEX`, a view definition, and
|
|
242
271
|
* so on.
|
|
@@ -246,6 +275,7 @@ export declare class CamusClient implements AsyncDisposable {
|
|
|
246
275
|
* deliver, and the driver refuses it before the round trip.
|
|
247
276
|
*/
|
|
248
277
|
executeDdl(sql: string, options?: AutocommitStatementOptions): Promise<boolean>;
|
|
278
|
+
private runDdl;
|
|
249
279
|
/**
|
|
250
280
|
* Inserts one row through the server's typed row-level route, naming a table and a column-to-value
|
|
251
281
|
* map instead of composing SQL.
|
|
@@ -258,6 +288,38 @@ export declare class CamusClient implements AsyncDisposable {
|
|
|
258
288
|
* health, and error translation. Use it to avoid building statement text for a hot write path.
|
|
259
289
|
*/
|
|
260
290
|
insert(table: string, values: Parameters, options?: StatementOptions): Promise<number>;
|
|
291
|
+
/** The endpoints that this client is configured with, in configuration order. */
|
|
292
|
+
get endpoints(): readonly string[];
|
|
293
|
+
/**
|
|
294
|
+
* The disk, CPU, and memory of one node. See `CamusNodeStats` for every field.
|
|
295
|
+
*
|
|
296
|
+
* ```ts
|
|
297
|
+
* const stats = await client.nodeStats();
|
|
298
|
+
* const data = stats.dataVolume!;
|
|
299
|
+
*
|
|
300
|
+
* console.log(`${data.availableBytes} bytes free of ${data.totalBytes}`);
|
|
301
|
+
*
|
|
302
|
+
* for (const endpoint of client.endpoints) {
|
|
303
|
+
* const node = await client.nodeStats(endpoint);
|
|
304
|
+
* console.log(`${node.address}: ${node.cpu.processCpuPercent}% CPU`);
|
|
305
|
+
* }
|
|
306
|
+
* ```
|
|
307
|
+
*
|
|
308
|
+
* Without `endpoint`, it asks the next node in the rotation. Each node answers only for itself.
|
|
309
|
+
* An `endpoint` must be one of `endpoints`, so the client's credentials go only to the addresses
|
|
310
|
+
* it was configured with.
|
|
311
|
+
*
|
|
312
|
+
* It is server-level, not scoped to this client's database, and it works over REST
|
|
313
|
+
* (`GET /v1/admin/stats`) and gRPC (`GetNodeStats`). With authentication on, the account needs
|
|
314
|
+
* the superuser attribute or the `MONITOR` privilege (`GRANT MONITOR ON *.* TO <user>`). Any
|
|
315
|
+
* other account gets `CADB0517`.
|
|
316
|
+
*
|
|
317
|
+
* @throws {TypeError} when `endpoint` is not one of `endpoints`.
|
|
318
|
+
*/
|
|
319
|
+
nodeStats(endpoint?: string, options?: {
|
|
320
|
+
signal?: AbortSignal;
|
|
321
|
+
timeoutSeconds?: number;
|
|
322
|
+
}): Promise<CamusNodeStats>;
|
|
261
323
|
/** Reports whether the server answers. */
|
|
262
324
|
ping(options?: {
|
|
263
325
|
signal?: AbortSignal;
|
|
@@ -280,6 +342,9 @@ export declare class CamusClient implements AsyncDisposable {
|
|
|
280
342
|
*
|
|
281
343
|
* With `await using`, a transaction that is left without a commit is rolled back as the block
|
|
282
344
|
* unwinds.
|
|
345
|
+
*
|
|
346
|
+
* With `deferBegin`, or with learned routing on, `BEGIN` is not sent here. The first statement,
|
|
347
|
+
* or the first `CamusPipeline` send, sends it.
|
|
283
348
|
*/
|
|
284
349
|
beginTransaction(options?: CamusTransactionOptions, signal?: AbortSignal): Promise<CamusTransaction>;
|
|
285
350
|
/**
|
|
@@ -299,6 +364,9 @@ export declare class CamusClient implements AsyncDisposable {
|
|
|
299
364
|
* an exponential back-off. So the function must be safe to run more than once — it must not send
|
|
300
365
|
* an email, charge a card, or mutate state outside the database on a path that could repeat.
|
|
301
366
|
*
|
|
367
|
+
* The work can commit the transaction itself with `CamusPipeline.commit`. The transaction is
|
|
368
|
+
* then not committed a second time.
|
|
369
|
+
*
|
|
302
370
|
* A commit that reports an unresolved outcome is **not** retried this way. That case is resolved
|
|
303
371
|
* inside `CamusTransaction`, by re-issuing the same commit on the same handle, because replaying
|
|
304
372
|
* the work could apply an already-durable commit twice.
|
|
@@ -442,8 +510,11 @@ export declare class CamusClient implements AsyncDisposable {
|
|
|
442
510
|
* without `RETURNING`, so this sets it on every statement and does not parse the SQL for the clause.
|
|
443
511
|
*/
|
|
444
512
|
private executeNonQuery;
|
|
445
|
-
/**
|
|
446
|
-
|
|
513
|
+
/**
|
|
514
|
+
* Runs a write with `RETURNING`, or a `CALL`, on the non-query route and maps the rows it sent
|
|
515
|
+
* back. A `CALL` sends back none.
|
|
516
|
+
*/
|
|
517
|
+
private queryNonQueryRoute;
|
|
447
518
|
/**
|
|
448
519
|
* Runs a write on the non-query route. The endpoint, the negotiation flag, and the learning after
|
|
449
520
|
* a success follow the same routing rules as the query path.
|
|
@@ -467,43 +538,6 @@ export declare class CamusClient implements AsyncDisposable {
|
|
|
467
538
|
*/
|
|
468
539
|
private route;
|
|
469
540
|
private buildRequest;
|
|
470
|
-
/**
|
|
471
|
-
* Whether this execution should name a prepared statement instead of carrying its SQL,
|
|
472
|
-
* registering it first when this is the execution that tips it over the threshold.
|
|
473
|
-
*
|
|
474
|
-
* The registration is awaited rather than started in the background, because the whole point is
|
|
475
|
-
* that this execution and the ones after it are cheap. Firing it off and running inline anyway
|
|
476
|
-
* would leave a busy statement racing its own warm-up. It costs one extra round trip, once per
|
|
477
|
-
* statement per endpoint.
|
|
478
|
-
*
|
|
479
|
-
* The caller passes the endpoint it already resolved. A REST handle is node-local and the pool
|
|
480
|
-
* rotates, so registering against a freshly drawn endpoint would routinely prepare on one node
|
|
481
|
-
* and execute on another — correct, because the transport re-registers where it lands, but a
|
|
482
|
-
* wasted round trip every single time.
|
|
483
|
-
*/
|
|
484
|
-
private shouldPrepare;
|
|
485
|
-
/**
|
|
486
|
-
* Registers a statement and records what happened, reporting whether it may now run prepared.
|
|
487
|
-
*
|
|
488
|
-
* A registration failure never reaches the caller: preparing is an optimization, and the
|
|
489
|
-
* statement runs inline exactly as it would have if the driver had not tried. What the failure
|
|
490
|
-
* does decide is whether to ask again. A refusal specific to this statement stops asking for that
|
|
491
|
-
* statement; anything that says the node has no prepared-statement support at all stops asking
|
|
492
|
-
* for every statement, because one round trip per distinct SQL to relearn that is worse than not
|
|
493
|
-
* trying. A failure that never reached a verdict — a timeout, an unreachable node — drops the
|
|
494
|
-
* entry instead, so one network blip does not cost this statement its registration for the life
|
|
495
|
-
* of the process.
|
|
496
|
-
*/
|
|
497
|
-
private register;
|
|
498
|
-
/**
|
|
499
|
-
* Releases a statement the policy evicted, so the server stops holding a handle this client has
|
|
500
|
-
* stopped using.
|
|
501
|
-
*
|
|
502
|
-
* It is best effort and off the caller's path: it is bookkeeping, not part of the statement being
|
|
503
|
-
* run. It takes the endpoint the caller already resolved rather than drawing a new one, which
|
|
504
|
-
* would rotate the pool as a side effect of housekeeping.
|
|
505
|
-
*/
|
|
506
|
-
private release;
|
|
507
541
|
/**
|
|
508
542
|
* The effective options for a transaction or an autocommit statement: the caller's explicit knobs
|
|
509
543
|
* win, then this client's defaults, then the server default for any knob still unset.
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|