6. State of the World¶
AMPS State of the World (SOW) allows you to automatically keep and query the latest information about a topic on the AMPS server, without building a separate database. Using SOW lets you build impressively high-performance applications that provide rich experiences to users. The AMPS JavaScript client lets you query SOW topics and subscribe to changes with ease.
Performing SOW Queries¶
To begin, we will look at a simple example of issuing a SOW query.
client.sow(
// Message handler
function(message) {
switch (message.header.command()) {
case 'group_begin':
console.log('--- Begin SOW Results ---');
break;
case 'sow':
console.log(message.data);
break;
case 'group_end':
console.log('--- End SOW Results ---');
break;
}
},
'orders', // SOW Topic
'/symbol="ROL"' // Filter
);
Example 6.1: Basic SOW query
In the above
Example 6.1
we invoke Client.sow()
to initiate a SOW query on the orders
topic, for all entries that have a symbol of 'ROL'
. As usual, the
Client.sow()
method returns a Promise
oject that resolves with
the query id.
As the query executes, the message handler function is invoked for each
matching entry in the topic. Messages containing the data of matching
entries have a Command
of value sow
, so as those arrive, we write
them to the console.
SOW and Subscribe¶
Imagine an application that displays real time information about the
position and status of a fleet of delivery vans. When the application
starts, it should display the current location of each of the vans along
with their current status. As vans move around the city and post other
status updates, the application should keep its display up to date. Vans
upload information to the system by posting message to an van
location
topic, configured with a key of van_id
on the AMPS
server.
In this application, it is important to not only stay up-to-date on the
latest information about each van, but to ensure all of the active vans
are displayed as soon as the application starts. Combining a SOW with a
subscription to the topic is exactly what is needed, and that is
accomplished by the Client.sowAndSubscribe()
method, or by executing
a sow_and_subscribe
command.
sowAndSubscribe()¶
First, let’s look at an example that uses the convenience method:
function reportVanPosition(client) {
/**
* sowAndSubscribe() method to begin receiving information about all
* of the active delivery vans in the system. All of the vans in the
* system now are returned as Message objects whose `message.c` field
* returns `sow`. New messages coming in are returned as Message
* objects whose `message.c` field returns `p` (publish).
*/
return client.sowAndSubscribe(
// Message handler
function(message) {
var cmdName = message.header.command();
if (cmdName === 'sow' || cmdName === 'p') {
/**
* For each of these messages we call addOrUpdateVan(),
* that presumably adds the van to our application’s
* display. As vans send updates to the AMPS server,
* those are also received by the client because of the
* subscription placed by sowAndSubscribe(). Our
* application does not need to distinguish between
* updates and the original set of vans we found via the
* SOW query, so we use addOrUpdateVan() to display
* the new position of vans as well.
*/
addOrUpdateVan(message);
}
else if (cmdName === 'oof') {
removeVan(message);
}
},
'van_location', // SOW Topic
'/status = "ACTIVE"', // Filter
// Additional parameters
{
batchSize: 100,
options: 'oof'
}
);
}
Example 6.2: Using sowAndSubscribe()
Execute a Command¶
Now we will look at an example that uses the Command
interface with the
Client.execute()
method:
function updateVanPosition(message) {
var cmdName = message.header.command();
if (cmdName === 'sow' or cmdName === 'p') {
addOrUpdateVan(message);
}
else if (cmdName === 'oof') {
removeVan(message);
}
}
function subscribeToVanLocation(client) {
return client.execute(
// Command object to execute
new amps.Command('sow_and_subscribe')
.topic('van_location')
.filter('/status = "ACTIVE"')
.batchSize(100)
.options('oof'),
// Message handler
updateVanPosition
);
}
Example 6.3: Using sow_and_subscribe
Notice that the two forms have the same result.
OOF Messages¶
In the above examples we specified the oof
option to the command.
Setting this option causes AMPS to send Out-of-Focus (“OOF”) messages for topic.
OOF messages are sent when an entry that was sent to us in the past no longer
matches our query. This happens when an entry is removed from the SOW cache via
a sow_delete
operation, when the entry expires (as specified by the expiration
time on the message or by the configuration of that topic on the AMPS server), or
when the entry no longer matches the content filter specified. In our case,
if a van’s status changes to something other than ACTIVE, it no longer matches
the content filter, and becomes out of focus. When this occurs, a message
is sent with Command
set to oof
. We use OOF messages to remove vans from
the display as they become inactive, expire, or are deleted.
Setting Batch Size¶
The AMPS clients include a batch size parameter that specifies how many messages the AMPS server will return to the client in a single batch when returning the results of a SOW query. The 60East clients set a batch size of 10 by default. This batch size works well for common message sizes and network configurations.
Adjusting the batch size may produce better network utilitization and produce better performance overall for the application. The larger the batch size, the more messages AMPS will send to the network layer at a time. This can result in fewer packets being sent, and therefore less overhead in the network layer. The effect on performance is generally most noticeable for small messages, where setting a larger batch size will allow several messages to fit into a single packet. For larger messages, a batch size may still improve performance, but the improvement is less noticeable.
In general, 60East recommends setting a batch size that is large enough to produce few partially-filled packets. Bear in mind that AMPS holds the messages in memory while batching them, and the client must also hold the messages in memory while receiving the messages. Using batch sizes that require large amounts of memory for these operations can reduce overall application peformance, even if network utilization is good.
For smaller message sizes, 60East recommends using the default batch size, and experimenting with tuning the batch size if performance improvements are necessary. For relatively large messages (especially messages with sizes over 1MB), 60East recommends explicitly setting a batch size of 1 as an initial value, and increasing the batch size only if performance testing with a larger batch size shows improved network utilization or faster overall performance.
Managing SOW Contents¶
AMPS allows applications to manage the contents of the SOW by explicitly deleting messages that are no longer relevant. For example, if a particular delivery van is retired from service, the application can remove the record for the van by deleting the record for the van.
The client provides the following methods for deleting records from the SOW:
sowDelete()
accepts a topic and filter, and deletes all messages that match the filter from the topic specifiedsowDeleteByKeys()
accepts a set of SOW keys as a comma-delimited string and deletes messages for those keys, regardless of the contents of the messages. SOW keys are provided in the header of a SOW message, and are the internal identifier AMPS uses for that SOW message.sowDeleteByData()
accepts a topic and message, and deletes the SOW record that would be updated by that message
Most applications use sowDelete()
, since this is the most useful and
flexible method for removing items from the SOW. In some cases,
particularly when working with extremely large SOW databases,
sowDeleteByKeys()
can provide better performance.
In either case, AMPS sends an OOF message to all subscribers who have received updates for the messages removed, as described in the previous section.
sowDelete()
returns a Promise that resolves with a Message
object.
This Message
is an acknowledgment that contains information on the
delete command. For example, the following snippet simply prints
informational text with the number of messages deleted:
client
.sowDelete('sow-topic', '/id IN (42, 64, 37)')
.then(function(ack) {
/**
* The following code will output something like:
* Got an ack message containing stats : deleted 10 SOW entries
*/
console.log(
'Got an',
ack.header.command(), 'message containing',
ack.header.ackType(), ': deleted',
ack.header.matches(), 'SOW entries'
);
});
Example 6.4: Using sowDelete()
Acknowledging messages from a queue uses a form of the sow_delete
command that is only supported for queues. Acknowledgment is discussed
in the chapter on queues.