|
2 | 2 | title: "LiveObjects pricing" |
3 | 3 | meta_description: "Understand how LiveObjects operations contribute to your message count, including LiveMap, LiveCounter, synchronization, and REST API usage." |
4 | 4 | meta_keywords: "LiveObjects pricing, message counting, LiveMap, LiveCounter, ObjectMessages" |
5 | | -intro: "How LiveObjects operations contribute to your message count." |
| 5 | +intro: "How LiveObjects operations contribute to your message count and strategies to optimize costs." |
6 | 6 | redirect_from: |
7 | 7 | - /docs/liveobjects/concepts/billing |
8 | 8 | --- |
9 | 9 |
|
10 | | -<If lang="javascript"> |
11 | | - <Aside data-type='public-preview'> |
12 | | - LiveObjects JavaScript is in Public Preview. Ably is committed to supporting the LiveObjects JavaScript API and welcomes adoption and feedback. |
13 | | - |
14 | | - **Building with LiveObjects?** Help shape its future by [sharing your use case](https://44qpp.share.hsforms.com/2fZobHQA1ToyRfB9xqZYQmQ). |
15 | | - </Aside> |
16 | | -</If> |
17 | | -<If lang="swift"> |
18 | | - <Aside data-type='experimental'> |
19 | | - LiveObjects Swift is currently Experimental. Its features are still in development and subject to rapid change. |
20 | | - |
21 | | - **Building with LiveObjects?** Help shape its future by [sharing your use case](https://44qpp.share.hsforms.com/2fZobHQA1ToyRfB9xqZYQmQ). |
22 | | - </Aside> |
23 | | -</If> |
24 | | -<If lang="java"> |
25 | | - <Aside data-type='experimental'> |
26 | | - LiveObjects Java is currently Experimental. Its features are still in development and subject to rapid change. |
27 | | - |
28 | | - **Building with LiveObjects?** Help shape its future by [sharing your use case](https://44qpp.share.hsforms.com/2fZobHQA1ToyRfB9xqZYQmQ). |
29 | | - </Aside> |
30 | | -</If> |
31 | | - |
32 | | -LiveObjects operations are billed using ObjectMessages. Each ObjectMessage follows the standard inbound/outbound counting pattern. |
33 | | - |
34 | | -<Aside data-type="further-reading"> |
35 | | -For how all Ably products count messages, see [message counting](/docs/platform/pricing/message-counting). For package comparison and volume discounts, see the [pricing](https://ably.com/pricing) page. |
36 | | -</Aside> |
| 10 | +Ably bills LiveObjects operations using ObjectMessages. An ObjectMessage is the unit of change in LiveObjects. Each state mutation, such as setting a key, incrementing a counter, or creating an object, generates one or more ObjectMessages. Each ObjectMessage follows the standard inbound/outbound counting pattern. |
37 | 11 |
|
38 | 12 | ## LiveObjects operations <a id="operations"/> |
39 | 13 |
|
40 | 14 | The following table shows how LiveObjects operations contribute to your message count: |
41 | 15 |
|
42 | 16 | | Operation | Messages counted | |
43 | 17 | | --- | --- | |
44 | | -| [LiveMap](#livemap-operations) set or remove | 1 inbound message per operation | |
45 | | -| [LiveMap](#livemap-operations) create (shallow) | 2 inbound messages (create + assign) | |
46 | | -| [LiveCounter](#livecounter-operations) increment or decrement | 1 inbound message | |
47 | | -| [LiveCounter](#livecounter-operations) create | 2 inbound messages (create + assign) | |
| 18 | +| [LiveMap](/docs/liveobjects/map) set or remove | 1 inbound message per operation | |
| 19 | +| [LiveMap](/docs/liveobjects/map) create (shallow) | 2 inbound messages (create + assign) | |
| 20 | +| [LiveCounter](/docs/liveobjects/counter) increment or decrement | 1 inbound message | |
| 21 | +| [LiveCounter](/docs/liveobjects/counter) create | 2 inbound messages (create + assign) | |
48 | 22 | | ObjectMessage delivery | 1 outbound message per connected client | |
49 | 23 | | [Synchronization](#synchronization) | 1 message per object synchronized | |
50 | 24 | | [REST API](#rest-api) fetch | 1 message per object in response | |
51 | | -| [Batch](#livemap-operations) operation | 1 message per operation in the batch | |
| 25 | +| [Batch](/docs/liveobjects/batch) operation | 1 message per operation in the batch | |
52 | 26 |
|
53 | | -Nested object creation generates additional messages for each nested object. See the [examples below](#livemap-operations) for details. |
| 27 | +Nested object creation generates additional messages for each nested object. |
| 28 | + |
| 29 | +<Aside data-type="further-reading"> |
| 30 | +For how all Ably products count messages, see [message counting](/docs/platform/pricing/message-counting). |
| 31 | +</Aside> |
54 | 32 |
|
55 | 33 | ## Channels and connections <a id="channels-connections"/> |
56 | 34 |
|
57 | 35 | Each LiveObjects channel contributes to your [channel count](/docs/platform/pricing#channels). Ably bills [connection minutes](/docs/platform/pricing#connections) per minute of connection time for each connected client. |
58 | 36 |
|
59 | 37 | Subscribing to updates does not affect the number of messages received by a client. Any client attached to a channel with the `object-subscribe` capability automatically receives all object messages for that channel. Subscribing to updates on an object adds a listener that is called whenever the client receives updates for that object. |
60 | 38 |
|
61 | | -<If lang="javascript"> |
62 | | - |
63 | | -## LiveMap operation examples <a id="livemap-operations"/> |
64 | | - |
65 | | -Removing a key and setting a primitive value always sends one message: |
66 | | - |
67 | | -<Code> |
68 | | -```javascript |
69 | | -// One message |
70 | | -await myObject.get('settings').set('theme', 'dark'); |
71 | | - |
72 | | -// One message |
73 | | -await myObject.get('settings').remove('theme'); |
74 | | -``` |
75 | | -</Code> |
76 | | - |
77 | | -Creating a shallow `LiveMap` sends two messages: one to create the new `LiveMap` object, and one to assign it to the target object: |
78 | | - |
79 | | -<Code> |
80 | | -```javascript |
81 | | -// Two messages: create map + assign to 'settings' |
82 | | -await myObject.set('settings', LiveMap.create({ |
83 | | - shallow: 'data' |
84 | | -})); |
85 | | -``` |
86 | | -</Code> |
87 | | - |
88 | | -Nested `LiveMap` or `LiveCounter` objects each generate their own creation messages: |
89 | | - |
90 | | -<Code> |
91 | | -```javascript |
92 | | -// Four messages: |
93 | | -// - create visits counter |
94 | | -// - create stats map |
95 | | -// - create settings map |
96 | | -// - assign to 'settings' |
97 | | -await myObject.set('settings', LiveMap.create({ |
98 | | - stats: LiveMap.create({ |
99 | | - visits: LiveCounter.create() |
100 | | - }) |
101 | | -})); |
102 | | -``` |
103 | | -</Code> |
104 | | - |
105 | | -Batch operations result in a message for each operation included in the batch: |
106 | | - |
107 | | -<Code> |
108 | | -```javascript |
109 | | -// Four messages |
110 | | -await myObject.get('settings').batch((ctx) => { |
111 | | - ctx.set('theme', 'dark'); |
112 | | - ctx.set('fontSize', 14); |
113 | | - ctx.set('notifications', true); |
114 | | - ctx.remove('oldSetting'); |
115 | | -}); |
116 | | -``` |
117 | | -</Code> |
118 | | - |
119 | | -## LiveCounter operation examples <a id="livecounter-operations"/> |
120 | | - |
121 | | -Incrementing and decrementing a counter always sends one message: |
122 | | - |
123 | | -<Code> |
124 | | -```javascript |
125 | | -// One message |
126 | | -await myObject.get('visits').increment(5); |
127 | | - |
128 | | -// One message |
129 | | -await myObject.get('visits').decrement(3); |
130 | | -``` |
131 | | -</Code> |
132 | | - |
133 | | -Creating a `LiveCounter` sends two messages: one to create the new `LiveCounter` object, and one to assign it to the target object: |
134 | | - |
135 | | -<Code> |
136 | | -```javascript |
137 | | -// Two messages: create counter + assign to 'visits' |
138 | | -await myObject.set('visits', LiveCounter.create(0)); |
139 | | -``` |
140 | | -</Code> |
141 | | - |
142 | | -Creating a counter nested within a `LiveMap` also generates messages for the parent map: |
143 | | - |
144 | | -<Code> |
145 | | -```javascript |
146 | | -// Four messages: |
147 | | -// - create visits counter |
148 | | -// - create stats map |
149 | | -// - create settings map |
150 | | -// - assign to 'settings' |
151 | | -await myObject.set('settings', LiveMap.create({ |
152 | | - stats: LiveMap.create({ |
153 | | - visits: LiveCounter.create(0) |
154 | | - }) |
155 | | -})); |
156 | | -``` |
157 | | -</Code> |
158 | | - |
159 | | -Batch operations result in a message for each operation included in the batch: |
160 | | - |
161 | | -<Code> |
162 | | -```javascript |
163 | | -// Three messages |
164 | | -await myObject.get('visits').batch((ctx) => { |
165 | | - ctx.increment(5); |
166 | | - ctx.increment(3); |
167 | | - ctx.decrement(2); |
168 | | -}); |
169 | | -``` |
170 | | -</Code> |
171 | | - |
172 | | -</If> |
| 39 | +## Cost optimization <a id="optimization"/> |
| 40 | + |
| 41 | +### Prefer flat data structures |
| 42 | + |
| 43 | +Setting a primitive value on a LiveMap costs one message. Creating a nested LiveMap costs two or more messages (one to create the object, one to assign it), plus additional messages for each level of nesting. Flatten your data model where possible to reduce the number of messages per update. |
| 44 | + |
| 45 | +### Minimize objects per channel |
| 46 | + |
| 47 | +Each object on a channel is synchronized when a client attaches or resynchronizes. Fewer objects per channel reduces the cost of synchronization. Distribute objects across channels based on which clients need access to them. |
173 | 48 |
|
174 | 49 | ## Synchronization <a id="synchronization"/> |
175 | 50 |
|
176 | | -During initial synchronization and resynchronization, each object on the channel is sent as a message. |
| 51 | +During initial synchronization and resynchronization, Ably sends each object on the channel as a message. |
177 | 52 |
|
178 | | -For example, if a channel contains 10 objects (such as `LiveMap` and `LiveCounter` instances), a client attaching to the channel will receive 10 messages during synchronization. |
| 53 | +For example, if a channel contains 10 objects (such as `LiveMap` and `LiveCounter` instances), a client attaching to the channel receives 10 messages during synchronization. |
179 | 54 |
|
180 | | -Similarly, if a client becomes disconnected and needs to resynchronize, it will receive messages for each object that needs to be synchronized. |
| 55 | +Similarly, if a client becomes disconnected and needs to resynchronize, it receives messages for each object that needs to be synchronized. |
181 | 56 |
|
182 | 57 | Only [reachable](/docs/liveobjects/concepts/objects#reachability) objects are counted. Ably may send [tombstone](/docs/liveobjects/concepts/objects#tombstones) objects to the client, but these will not count towards your usage. |
183 | 58 |
|
|
0 commit comments