Skip to content

Commit 45fe9ba

Browse files
committed
Docs
1 parent 0fc0b6e commit 45fe9ba

File tree

2 files changed

+65
-1
lines changed

2 files changed

+65
-1
lines changed

README.md

+64
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,16 @@ which is closer to the underlying DynamoDB API:
6868
let updated = table.UpdateItem <@ fun r -> SET r.Name "newName" &&& ADD r.Dependencies ["MBrace.Core.dll"] @>
6969
```
7070

71+
Preconditions that are not upheld are signalled via an `Exception` by the underlying AWS SDK. These can be trapped using the supplied exception filter:
72+
73+
```fsharp
74+
try let! updated = table.UpdateItemAsync(<@ fun r -> { r with Started = Some DateTimeOffset.Now } @>,
75+
preCondition = <@ fun r -> r.DateTimeOffset = None @>)
76+
return Some updated
77+
with Precondition.CheckFailed ->
78+
return None
79+
```
80+
7181
## Supported Field Types
7282

7383
`FSharp.AWS.DynamoDB` supports the following field types:
@@ -240,8 +250,62 @@ table.Scan(startedBefore (DateTimeOffset.Now - TimeSpan.FromDays 1.))
240250

241251
(See [`Script.fsx`](src/FSharp.AWS.DynamoDB/Script.fsx) for example timings showing the relative efficiency.)
242252

253+
## `TransactWriteItems`
254+
255+
[`TransactWriteItems`](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html) lets you (at a high level; there are [some key differences](https://stackoverflow.com/a/71706015/11635) in how the APIs are structured)
256+
compose multiple write transactions into an aggregate request that will succeed or fail atomically. See this [excellent overview article](https://www.alexdebrie.com/posts/dynamodb-transactions) by [@alexdebrie](https://github.com/alexdebrie) and
257+
[the `TransactWriteItems` API documentation](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html) for full semantics
258+
(e.g., the full API lets you compose transactions across tables - the present implementation does not attempt to expose that facility,
259+
and there are diverse constraints such as the fact that no item may have more than one operation applied to it within the overall transaction).
260+
261+
Conditions and update expressions are taken in the [precompiled](#Precomputing-DynamoDB-Expressions) form.
262+
263+
The supported operations are:
264+
- `Check` - a `ConditionCheck` operation on a specified `key` supplied as a (compiled) `condition`
265+
- `Put` - a `PutItem`-equivalent operation that upserts a supplied `item` (with an `option`al `precondition`)
266+
- `Update` - an `UpdateItem`-equivalent operation that applies a specified `updater` expression to an item with a specified `key` (with an `option`al `precondition`)
267+
- `Delete` - a `DeleteItem`-equivalent operation that deletes the item with a specified `key` (with an `option`al `precondition`)
268+
269+
```fsharp
270+
let compile = table.Template.PrecomputeConditionalExpr
271+
let doesntExistCondition = compile <@ fun t -> NOT_EXISTS t.Value @>
272+
let existsCondition = compile <@ fun t -> EXISTS t.Value @>
273+
274+
let key = TableKey.Combined(hashKey, rangeKey)
275+
let requests = [
276+
TransactWrite.Check (key, doesntExistCondition)
277+
TransactWrite.Put (item2, None)
278+
TransactWrite.Put (item3, Some existaCondition)
279+
TransactWrite.Delete (table.Template.ExtractKey item5, None) ]
280+
do! table.TransactWriteItems requests
281+
```
282+
283+
Failed preconditions (or `TransactWrite.Check` requests) are signalled as per the underlying API, via a `TransactionCanceledException`.
284+
Use `TransactWriteItemsRequest.TransactionCanceledConditionalCheckFailed` to trap such conditions:
285+
286+
```fsharp
287+
try do! table.TransactWriteItems writes
288+
return Some result
289+
with TransactWriteItemsRequest.TransactionCanceledConditionalCheckFailed -> return None
290+
```
291+
292+
See the [`TransactWriteItems tests`](./tests/FSharp.AWS.DynamoDB.Tests/SimpleTableOperationTests.fs#130) for more details and examples.
293+
294+
It should be noted that the [request charging structures](#request-charging-structures) are such that you'll pay double
295+
or more the Write Capacity Units in charges per constituent `TransactItem` of which the transaction is composed when compared to
296+
expressing equivalent semantics as precondition expressions, so they should only be used where absolutely required.
297+
298+
## Request Charging Structures
299+
300+
The key to using DynamoDB (really, any rate-limited store) is to invest time before, during and after you design your table structure,
301+
updates and queries to understand the charging structure and how its affecting the efficiency of your application inside out.
302+
Here's a [good overview article](https://zaccharles.medium.com/calculating-a-dynamodb-items-size-and-consumed-capacity-d1728942eb7c),
303+
but no single article will convey the complete picture - reading and observing charges empirically should not be an afterthought.
304+
243305
## Observability
244306

307+
Critical to any production deployment is to ensure that you have good insight into the costs your application is incurring at runtime.
308+
245309
A hook is provided so metrics can be published via your preferred Observability provider. For example, using [Prometheus.NET](https://github.com/prometheus-net/prometheus-net):
246310

247311
```fsharp

tests/FSharp.AWS.DynamoDB.Tests/SimpleTableOperationTests.fs

+1-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ type ``Simple Table Operation Tests`` (fixture : TableFixture) =
128128

129129
interface IClassFixture<TableFixture>
130130

131-
type TransactWriteItems(fixture : TableFixture) =
131+
type ``TransactWriteItems tests``(fixture : TableFixture) =
132132

133133
let rand = let r = Random() in fun () -> int64 <| r.Next()
134134
let mkItem() =

0 commit comments

Comments
 (0)