WEBVTT

NOTE Created by CaptionSync from Automatic Sync Technologies www.automaticsync.com

00:00:00.276 --> 00:00:06.256 align:middle
Hello, my name is Jeremy Mikola.

00:00:06.256 --> 00:00:10.116 align:middle
We have 40 minutes and 58
slides, so I will try to be brief

00:00:10.116 --> 00:00:13.126 align:middle
and there probably will not
be time for questions.

00:00:13.256 --> 00:00:19.966 align:middle
I will be outside and catch me
before tomorrow, etc. Um, welcome.

00:00:20.636 --> 00:00:22.016 align:middle
A little bit about myself.

00:00:22.326 --> 00:00:23.176 align:middle
I'll make this very brief.

00:00:23.446 --> 00:00:26.016 align:middle
I've been in the Symfony community for a while.

00:00:26.306 --> 00:00:31.206 align:middle
I missed Cluj last year, but I've
been to most of the other conferences.

00:00:31.206 --> 00:00:33.546 align:middle
Later join me on the main stage for Jeopardy.

00:00:34.576 --> 00:00:37.456 align:middle
I work for MongoDB, it's been
about six and a half years now,

00:00:37.776 --> 00:00:40.406 align:middle
which is longer than I expected it to be.

00:00:40.406 --> 00:00:43.886 align:middle
It's still taking good care of me and they keep
giving me more clothes, so I'm happy there.

00:00:43.886 --> 00:00:49.066 align:middle
We might have a WurstCon tomorrow, but
these days, I work less with Symfony.

00:00:49.216 --> 00:00:52.036 align:middle
I work on the MongoDB driver and Doctrine.

00:00:52.476 --> 00:00:55.986 align:middle
Andreas is here and there's some other folks
from Doctrine here I think this weekend.

00:00:56.806 --> 00:00:58.856 align:middle
So that's mainly what I work on.

00:00:59.136 --> 00:01:00.776 align:middle
Um, I did not get fired for this.

00:01:00.776 --> 00:01:02.586 align:middle
This is MongoDB snapchat for databases.

00:01:02.586 --> 00:01:03.796 align:middle
Uh, this was a few years ago.

00:01:03.866 --> 00:01:06.706 align:middle
I'm still employed, happily.

00:01:07.316 --> 00:01:12.106 align:middle
And so just an overview of what
I want to talk about today.

00:01:12.106 --> 00:01:14.576 align:middle
The subject was a little
strange with bulletproof MongoDB.

00:01:14.796 --> 00:01:18.316 align:middle
But I want, kind of a best practices talk
and talk about some of the newer features

00:01:19.486 --> 00:01:25.856 align:middle
that take us away from, whereas a few years ago
this was maybe more relevant that the criticisms

00:01:25.856 --> 00:01:29.626 align:middle
to MongoDB, but there's more new features
that give it more maturity and stability.

00:01:29.626 --> 00:01:30.656 align:middle
So I want to cover.

00:01:30.996 --> 00:01:34.336 align:middle
So I'm going to start by just a show of hands.

00:01:34.336 --> 00:01:39.336 align:middle
How many people are familiar with using MongoDB
in production or playing around with it first.

00:01:39.336 --> 00:01:39.736 align:middle
Okay, great.

00:01:40.356 --> 00:01:41.116 align:middle
That's about half.

00:01:41.486 --> 00:01:43.516 align:middle
So we'll talk a little bit
about deployment models.

00:01:43.616 --> 00:01:47.586 align:middle
I think for development environments, a
lot of us use just a single mongod process,

00:01:47.586 --> 00:01:49.396 align:middle
we don't use clusters or anything.

00:01:49.826 --> 00:01:54.116 align:middle
But talk a little bit about that because of the
better concepts definitely work with clusters.

00:01:54.586 --> 00:01:58.256 align:middle
Talk a little bit about how the driver
works specifically the php driver,

00:01:58.256 --> 00:02:02.276 align:middle
which makes a lot of, have to do special
behaviors because it's, we don't have threads,

00:02:02.276 --> 00:02:05.246 align:middle
we don't have a lot of the other features
that things like Java and Python have.

00:02:06.136 --> 00:02:11.106 align:middle
And then talk about designing applications
and the three subjects there are some concepts

00:02:11.106 --> 00:02:14.836 align:middle
that you can apply to your application, how,
what are the best practices for error handling

00:02:15.236 --> 00:02:19.966 align:middle
and how do we take advantage of transactions,
which is a newer feature within the last year

00:02:19.966 --> 00:02:25.446 align:middle
of having actual ACID transactions that
you'd find in a relational database.

00:02:25.446 --> 00:02:27.546 align:middle
That's the talk.

00:02:28.926 --> 00:02:30.636 align:middle
Please leave feedback on joind.in.

00:02:30.866 --> 00:02:34.766 align:middle
Is this going to happen regularly
or is there a presentation mode?

00:02:34.986 --> 00:02:47.406 align:middle
Yeah, that's what happens if he
doesn't go through the slides quickly.

00:02:47.846 --> 00:02:51.376 align:middle
That's a good password.

00:02:51.886 --> 00:02:54.066 align:middle
Yep. There we go.

00:02:55.546 --> 00:02:55.816 align:middle
We're good?

00:02:56.296 --> 00:02:57.676 align:middle
Yeah. Well, I think we're good.

00:02:58.596 --> 00:03:01.016 align:middle
Yeah, disable the screensaver.

00:03:01.016 --> 00:03:10.306 align:middle
So if you want to know what to do (inaudible).

00:03:10.806 --> 00:03:12.166 align:middle
Sorry about that.

00:03:12.166 --> 00:03:13.866 align:middle
Thanks Andreas.

00:03:14.246 --> 00:03:19.006 align:middle
So the basic is a standalone,
this is just running one mongod.

00:03:19.006 --> 00:03:23.096 align:middle
This is a good development environment,
my production websites, I'll just use this

00:03:23.096 --> 00:03:25.616 align:middle
because I have everything on one linode.

00:03:25.616 --> 00:03:27.256 align:middle
This is: everything stands alone.

00:03:27.546 --> 00:03:31.296 align:middle
You don't want to do this in production.

00:03:31.296 --> 00:03:35.226 align:middle
The two main things that you would want to
deploy your database is one with replication,

00:03:35.756 --> 00:03:40.936 align:middle
this should at least have three MongoD
processes on different machines and your client

00:03:40.936 --> 00:03:44.906 align:middle
and driver is talking to the, um, in a
cluster, you have one that is the one

00:03:44.906 --> 00:03:47.336 align:middle
that you can write to, and
usually you also read from,

00:03:47.336 --> 00:03:50.736 align:middle
and then the secondaries are
constantly replicating the same data.

00:03:51.546 --> 00:03:56.526 align:middle
And they're also communicating with each
other to keep aware if one of them disappears.

00:03:56.526 --> 00:04:01.426 align:middle
So if the primary server was to
crash or fail over, you take it down,

00:04:01.706 --> 00:04:06.716 align:middle
someone unplugs the network cable, you still
have two out of three and they can take over.

00:04:06.986 --> 00:04:08.606 align:middle
And one of them will become the new primary.

00:04:08.896 --> 00:04:13.956 align:middle
And your application goes from talking to
this primary to talking to the next one.

00:04:14.896 --> 00:04:17.616 align:middle
And so those are, when we talk about
failures and recovering from failures,

00:04:17.616 --> 00:04:20.496 align:middle
this is a very common thing
where a machine goes down

00:04:20.636 --> 00:04:23.316 align:middle
or you're doing maintenance or things like that.

00:04:23.876 --> 00:04:28.316 align:middle
Uh, and then more advanced, which I expect maybe
less people are using is with a shard cluster.

00:04:28.796 --> 00:04:34.946 align:middle
And this is where you have your app servers and
you would have another cluster of replica sets,

00:04:35.126 --> 00:04:38.706 align:middle
another three that store the
configuration for where data is stored here.

00:04:38.796 --> 00:04:45.566 align:middle
And then similar to sharding in a SQL database,
you'll have your data split across, sorry,

00:04:45.566 --> 00:04:47.906 align:middle
you'll have your data split
across multiple shards.

00:04:48.646 --> 00:04:54.526 align:middle
And typically in this case, you might
have a very large collection say...

00:04:56.106 --> 00:04:56.836 align:middle
where is it...

00:04:57.096 --> 00:04:58.676 align:middle
your user accounts maybe a smaller collection,

00:04:58.676 --> 00:05:01.826 align:middle
but your big collection may be all the
photos they're posting all the tweets

00:05:01.826 --> 00:05:02.376 align:middle
that they're posting.

00:05:02.376 --> 00:05:04.596 align:middle
So you would split that across multiple shards.

00:05:04.596 --> 00:05:08.436 align:middle
And this would be horizontal scaling, it was
discussed in some other talks earlier today.

00:05:08.436 --> 00:05:10.406 align:middle
But that's, you're spreading out instead

00:05:10.406 --> 00:05:13.736 align:middle
of making a bigger Amazon
instance or scaling vertically.

00:05:14.306 --> 00:05:19.646 align:middle
And because you can have hundreds or thousands
of shards, we have another process that kind

00:05:19.646 --> 00:05:23.126 align:middle
of acts like a router so that the driver does
not have to, the php driver does not have

00:05:23.126 --> 00:05:27.206 align:middle
to open up, in this case, this
is a comically large php app

00:05:27.206 --> 00:05:29.676 align:middle
where you have fpm workers
and they all put in sockets.

00:05:30.146 --> 00:05:33.036 align:middle
So you want to avoid the
case where we have thousands

00:05:33.036 --> 00:05:35.166 align:middle
of connections being opened
by every php process.

00:05:35.646 --> 00:05:37.936 align:middle
So there we would go through a routing process.

00:05:38.866 --> 00:05:43.786 align:middle
So those are the two basic deployment models:
sharded cluster and then a replica set.

00:05:44.326 --> 00:05:45.936 align:middle
And they leverage each other.

00:05:45.936 --> 00:05:48.256 align:middle
So sharding, uses replication internally.

00:05:48.256 --> 00:05:49.696 align:middle
And then if you're a smaller application,

00:05:49.696 --> 00:05:51.866 align:middle
you don't need to scale out,
you would just use replication.

00:05:52.836 --> 00:05:57.816 align:middle
But the driver different than, you say that
the PDO MySQL driver, it will typically talk

00:05:57.816 --> 00:06:02.106 align:middle
to one server at a time, whereas most of the
MongoDB drivers are responsible for doing,

00:06:02.676 --> 00:06:04.916 align:middle
talking to the entire cluster
of database servers.

00:06:05.366 --> 00:06:08.666 align:middle
And this is also different from, if
a driver, if anyone uses Cassandra

00:06:09.236 --> 00:06:12.996 align:middle
from the last presentation, I remember
going to Cassandra, there the driver talks

00:06:12.996 --> 00:06:15.406 align:middle
to one node and that talks to everyone else.

00:06:15.726 --> 00:06:21.326 align:middle
So in most other databases, the drivers
talk to a single database node at a time.

00:06:21.496 --> 00:06:26.036 align:middle
But taking just a dive through what
the PHP driver does when you use it.

00:06:26.166 --> 00:06:29.946 align:middle
So we start with a connection string,
which is similar to if use Doctrine

00:06:30.356 --> 00:06:32.506 align:middle
with a relational database there's a DSN.

00:06:32.506 --> 00:06:34.176 align:middle
This is very similar.

00:06:34.526 --> 00:06:36.806 align:middle
We have specifications that
tell us how to parse this.

00:06:36.886 --> 00:06:38.216 align:middle
So it kind of looks like an http url.

00:06:38.216 --> 00:06:43.606 align:middle
We have host identifiers, so maybe this
case it's one server, but if it's a cluster,

00:06:43.606 --> 00:06:46.366 align:middle
it could be comma with multiple
servers that you might talk to.

00:06:47.536 --> 00:06:51.676 align:middle
And there is additional and DNS if
anyone's familiar with SRV records.

00:06:51.676 --> 00:06:53.586 align:middle
And this is something that was added recently,

00:06:54.026 --> 00:06:57.886 align:middle
instead of having to maintain
constantly changing connection strings,

00:06:57.886 --> 00:07:01.896 align:middle
if you add more nodes to your cluster, we
can use DNS to keep track of that for us,

00:07:01.896 --> 00:07:04.996 align:middle
which makes maintenance easier
for the very large customers.

00:07:05.856 --> 00:07:07.936 align:middle
So this is something that
our cloud provider uses.

00:07:07.936 --> 00:07:10.866 align:middle
We have a cloud service in
MongoDB and it uses SRV records

00:07:10.866 --> 00:07:12.246 align:middle
to give you shorter connection strings.

00:07:12.506 --> 00:07:17.086 align:middle
And now once we parse a connection
string, we know that's maybe one

00:07:17.086 --> 00:07:18.346 align:middle
or two servers that we have to talk to.

00:07:18.346 --> 00:07:19.446 align:middle
We need to discover everyone.

00:07:20.016 --> 00:07:21.906 align:middle
So we're going to start by doing a handshake.

00:07:21.906 --> 00:07:27.956 align:middle
We know a few servers that we can talk to,
we reach out to them, we send them a command,

00:07:28.606 --> 00:07:32.606 align:middle
and that is basically an exchange of
knowing what protocols does the server speak

00:07:32.606 --> 00:07:35.776 align:middle
because there's many different versions,
and what protocols does the driver speak.

00:07:36.066 --> 00:07:40.246 align:middle
And this carries over with, if we're doing
authentication, if we're doing compression,

00:07:40.246 --> 00:07:44.476 align:middle
a zlib or snappy compression
for the protocol messages,

00:07:45.066 --> 00:07:47.016 align:middle
we just want to negotiate
what features are available.

00:07:47.896 --> 00:07:51.426 align:middle
And I'm rushing through a lot of
this but the slides are very verbose,

00:07:51.426 --> 00:07:54.616 align:middle
but everything references, if you'd like to
look this up later, I'll share the slides.

00:07:55.486 --> 00:07:59.266 align:middle
So once the driver talks to the server,
it know, well we support this compression.

00:07:59.266 --> 00:08:01.616 align:middle
We support this authentication mechanism.

00:08:02.336 --> 00:08:06.776 align:middle
The next step is to now we would go
through authentication and we'd say I want

00:08:06.776 --> 00:08:09.336 align:middle
to start discovering who else is in the cluster.

00:08:09.386 --> 00:08:12.856 align:middle
So if it was a replica set and maybe
we just connected to that one primary,

00:08:13.226 --> 00:08:16.446 align:middle
we do want to reach out and know
who the secondary servers are.

00:08:17.556 --> 00:08:21.076 align:middle
With a shard cluster it might just be
talking to multiple router processes.

00:08:22.126 --> 00:08:25.786 align:middle
And so this we call server discovery and
monitoring, we abbreviate it as SDAM.

00:08:25.786 --> 00:08:27.996 align:middle
It's one of the larger specifications.

00:08:27.996 --> 00:08:30.406 align:middle
It's one of the more complicated
ones that all the drivers have to do.

00:08:30.406 --> 00:08:35.136 align:middle
But this defines how we have a bunch of sockets
talking to servers and how we monitor them

00:08:35.216 --> 00:08:39.326 align:middle
to keep track of new servers showing up old
servers, going away, getting network errors.

00:08:40.946 --> 00:08:45.296 align:middle
And before we even talk to the servers, we know
from the connection string, maybe we can infer

00:08:45.296 --> 00:08:48.376 align:middle
that there's a certain, we think we're talking
to a shard cluster, we think we're talking

00:08:48.376 --> 00:08:51.696 align:middle
to a replica set, but once we actually
start getting responses then we know

00:08:51.696 --> 00:08:55.276 align:middle
for sure what kind of servers
that we're talking to.

00:08:56.196 --> 00:08:58.406 align:middle
And so this is where things start deviating.

00:08:58.406 --> 00:09:02.026 align:middle
And we have a multithreaded
drivers, think of like a Java app

00:09:02.026 --> 00:09:06.696 align:middle
where they have large app servers, with request
handlers and threads, and there's one instance

00:09:06.696 --> 00:09:07.926 align:middle
of the driver running on the app server.

00:09:08.426 --> 00:09:11.816 align:middle
and then the other example where
we had all the boxes on top.

00:09:12.036 --> 00:09:16.166 align:middle
In a php app, with typically fpm, you
have hundreds, thousands of workers

00:09:16.166 --> 00:09:18.976 align:middle
across a large app, a fleet of app servers.

00:09:18.976 --> 00:09:22.276 align:middle
And so collectively a single
threaded app like php is going

00:09:22.276 --> 00:09:26.366 align:middle
to open a lot more connections on MongoDB side.

00:09:26.366 --> 00:09:30.486 align:middle
As well as, just in the individual app
server, if you have each php worker,

00:09:30.926 --> 00:09:35.736 align:middle
we can't share things between PHP workers
because every, in a php application,

00:09:35.736 --> 00:09:37.236 align:middle
everything shares nothing with the other.

00:09:37.446 --> 00:09:42.706 align:middle
It's kind of a design point of PHP is that we
share nothing with the other php app servers.

00:09:43.246 --> 00:09:46.306 align:middle
So it definitely complicates things
in how we have to deal with talking

00:09:46.306 --> 00:09:48.416 align:middle
to a distributed database cluster.

00:09:49.446 --> 00:09:51.096 align:middle
So we need different approaches to monitoring.

00:09:51.646 --> 00:09:55.986 align:middle
And in a Java driver, Node JS, if
we have a multithreaded asynchronous

00:09:55.986 --> 00:10:00.166 align:middle
or we could have a background thread that's
in a connection pool, which is more common.

00:10:00.166 --> 00:10:03.596 align:middle
And then if you look at php, a
lot of database drivers in php,

00:10:03.596 --> 00:10:06.276 align:middle
there's no reason to use
connection pools because we can't...

00:10:07.576 --> 00:10:09.756 align:middle
most sane people are not using threads in php.

00:10:09.756 --> 00:10:14.686 align:middle
And so typically a php database
driver, we persist the socket.

00:10:15.256 --> 00:10:19.786 align:middle
So the PHP request comes in, we'll use the
socket, there's only one thing running at a time

00:10:19.786 --> 00:10:22.806 align:middle
and when we're done with that php
request, we leave the socket open

00:10:22.806 --> 00:10:24.186 align:middle
for the next request that gets served.

00:10:24.626 --> 00:10:26.276 align:middle
So for an FPM worker, that makes sense.

00:10:26.676 --> 00:10:29.426 align:middle
The first worker will open the connection
and then every other php request

00:10:29.426 --> 00:10:31.426 align:middle
that got served can use the same socket.

00:10:32.106 --> 00:10:36.576 align:middle
And that saves us the time of setting up
SSL and going through the whole handshake.

00:10:36.576 --> 00:10:39.166 align:middle
We can kind of inherit some of
the state that we're connected to.

00:10:40.416 --> 00:10:42.836 align:middle
So in a single-threaded, separate
sockets would be redundant.

00:10:42.836 --> 00:10:49.486 align:middle
We don't do connection pooling, it doesn't
really make sense for php's design.

00:10:49.486 --> 00:10:51.546 align:middle
And then there's different improvements
that we can make for monitoring.

00:10:51.546 --> 00:10:56.686 align:middle
So there's a concept of when, just in php
itself, when you do, when you work with streams

00:10:56.686 --> 00:10:59.986 align:middle
or in other database drivers,
you have a socket timeout in php,

00:10:59.986 --> 00:11:02.626 align:middle
which is the default socket timeout INI setting.

00:11:03.126 --> 00:11:05.956 align:middle
For some reason php defaults that to 60 seconds,

00:11:05.956 --> 00:11:08.796 align:middle
even though the PHP execution
time is 30 seconds.

00:11:09.416 --> 00:11:14.836 align:middle
So it's quite possible that you would timeout
talking to doing a fopen or doing a http request

00:11:14.836 --> 00:11:18.496 align:middle
in guzzle or something and your
php scripts would die giving up.

00:11:18.496 --> 00:11:19.976 align:middle
So those defaults are a bit odd.

00:11:19.976 --> 00:11:23.616 align:middle
But in the Mongo driver, we have a socket
timeout and that's us talking to the database,

00:11:23.616 --> 00:11:26.386 align:middle
and then a connect timeout is for
us establishing the connection.

00:11:26.806 --> 00:11:29.666 align:middle
So logically we'd like this to be
a bit smaller than socket timeout.

00:11:30.306 --> 00:11:33.306 align:middle
Socket timeout is going to be you
running queries and doing other things

00:11:33.306 --> 00:11:34.276 align:middle
and those are going to take longer.

00:11:34.406 --> 00:11:37.876 align:middle
Connection timeout we want that to be quick: try
and connect to the server, if it's not there,

00:11:37.876 --> 00:11:41.176 align:middle
we'd like to know as soon as
possible so we can return an error.

00:11:41.336 --> 00:11:45.466 align:middle
And there's other improvements
that we can make here to kind

00:11:45.586 --> 00:11:47.056 align:middle
of do this for a single threaded driver.

00:11:47.056 --> 00:11:51.426 align:middle
We don't have a background thread, we have to
kind of do everything on demand monitoring.

00:11:52.176 --> 00:11:56.386 align:middle
So what we can do is use an event
loop internally to just kind of try

00:11:56.386 --> 00:12:00.606 align:middle
to monitor all the servers at once,
and waste as little bit of your time

00:12:00.606 --> 00:12:02.456 align:middle
so that your php script can continue executing.

00:12:02.626 --> 00:12:08.166 align:middle
And so with monitoring implemented,
I won't dwell too much on that,

00:12:08.166 --> 00:12:10.846 align:middle
the next part is for the
drivers to select servers.

00:12:10.846 --> 00:12:15.406 align:middle
So the driver connects to a bunch
of servers and now we have to,

00:12:15.406 --> 00:12:17.066 align:middle
when we do an operation, we need to talk to one.

00:12:17.066 --> 00:12:20.206 align:middle
So if we're doing a write,
we need to know maybe three

00:12:20.206 --> 00:12:22.126 align:middle
or four servers we're connected
to, which one is the primary.

00:12:22.286 --> 00:12:26.736 align:middle
If we're doing a read, we might be comfortable
sending the read to any one of the servers.

00:12:26.736 --> 00:12:28.186 align:middle
We can read from a secondary if we want to.

00:12:28.996 --> 00:12:32.626 align:middle
So this is a separate spec, just
for knowing how to select a server.

00:12:32.626 --> 00:12:37.176 align:middle
And for it's very simple for writes,
obviously there's only one we can talk to.

00:12:37.236 --> 00:12:39.796 align:middle
But again, for a single-threaded driver,
we don't have a background thread.

00:12:40.536 --> 00:12:43.766 align:middle
So the server selection is kind
of integrated with the monitoring.

00:12:43.886 --> 00:12:45.586 align:middle
They have to happen in the same logic.

00:12:45.586 --> 00:12:51.046 align:middle
And so how this fits in with PHP, if this
is a basic script, we construct a client,

00:12:51.356 --> 00:12:57.126 align:middle
we get a collection which is basically
a table, drop and insert and do a find.

00:12:57.546 --> 00:13:04.556 align:middle
In the very old driver, and even the new one,
people expected that the first communication

00:13:04.556 --> 00:13:07.456 align:middle
with the server would happen
when we construct a client.

00:13:07.456 --> 00:13:11.046 align:middle
We're actually, in the PHP driver, we're
deferring that until we actually need to talk

00:13:11.046 --> 00:13:15.886 align:middle
to a server, so you have no IO happening when we
construct a client, it's the first time we know

00:13:15.886 --> 00:13:18.416 align:middle
that we have to talk to a server is
when we're going to start monitoring,

00:13:18.806 --> 00:13:21.146 align:middle
try to get a server for the operation.

00:13:21.146 --> 00:13:26.836 align:middle
So the first operation here is going to be
trying to run a drop command, which is a DDL,

00:13:26.836 --> 00:13:29.406 align:middle
a database definition language
command to drop the collection.

00:13:29.976 --> 00:13:33.096 align:middle
That needs a writeable server so that
at that point we say we need a primary,

00:13:33.476 --> 00:13:37.536 align:middle
I'm going to go discover what the topology
is, get a primary, monitoring starts.

00:13:37.936 --> 00:13:41.356 align:middle
So the first exception you'd have
if there was no network connection,

00:13:41.356 --> 00:13:43.526 align:middle
it would be from the drop command.

00:13:44.176 --> 00:13:46.156 align:middle
And if you're curious, this is all the output.

00:13:46.156 --> 00:13:49.936 align:middle
So it's just inserting and dumping out the data.

00:13:49.936 --> 00:13:52.906 align:middle
And so this is internally
what happens, we construct,

00:13:53.096 --> 00:13:56.816 align:middle
we have a higher level composer
package that wraps our php extension.

00:13:57.536 --> 00:14:00.496 align:middle
And then server selection, if we look
inside what the drop command does,

00:14:00.496 --> 00:14:03.946 align:middle
you see the first thing it does is, I need a
primary server and then I'll run the operation.

00:14:04.176 --> 00:14:10.706 align:middle
And so that's basically trusting the
php driver to do monitoring and knowing

00:14:10.706 --> 00:14:13.586 align:middle
that it's a bit less efficient
than if we had background threads,

00:14:13.586 --> 00:14:17.056 align:middle
it would certainly be better, but we have
to basically do it on demand when we need

00:14:17.056 --> 00:14:18.596 align:middle
to do certain, when we need to access a server.

00:14:19.036 --> 00:14:22.526 align:middle
So, as far as configuring how all this
works, there's different use cases,

00:14:22.586 --> 00:14:26.596 align:middle
some people's applications want to fail quickly,
other people's applications you want the most,

00:14:26.596 --> 00:14:31.326 align:middle
you want to avoid errors at all costs
and you are comfortable waiting for that.

00:14:31.326 --> 00:14:35.306 align:middle
So there's a lot of different options
and flags available and these are things

00:14:35.306 --> 00:14:36.756 align:middle
that you would pass when
you construct your client.

00:14:37.406 --> 00:14:40.176 align:middle
So the first one that I mentioned
earlier is your connect timeout,

00:14:40.176 --> 00:14:42.376 align:middle
and this is when we do initial socket timeout.

00:14:42.616 --> 00:14:46.926 align:middle
I'm sorry, the initial timeout in
milliseconds for opening the connection.

00:14:47.206 --> 00:14:49.306 align:middle
And you'll find this, I think every other stream

00:14:49.306 --> 00:14:51.106 align:middle
or database driver has something
similar to this.

00:14:51.816 --> 00:14:55.626 align:middle
And there, our default, which is, probably
you would want to lower this considerably,

00:14:56.416 --> 00:14:58.826 align:middle
is 10 seconds, which is a safe legacy value.

00:14:59.256 --> 00:15:02.616 align:middle
Generally for this value, I think you'd
want to customize it to a little bit

00:15:02.616 --> 00:15:04.246 align:middle
above your latency to your server.

00:15:04.656 --> 00:15:10.296 align:middle
So if your servers are within one second
ping time, and usually maybe there are

00:15:10.296 --> 00:15:11.496 align:middle
like 50 or a hundred milliseconds.

00:15:11.496 --> 00:15:13.316 align:middle
So I might use 250 milliseconds for this.

00:15:13.726 --> 00:15:17.746 align:middle
And maybe double it, but certainly keep it below
10 seconds because what you want to optimize

00:15:17.746 --> 00:15:22.286 align:middle
for is if I start the php driver and I try
and do something and there's no server at all,

00:15:22.286 --> 00:15:24.476 align:middle
I don't want to wait 10 seconds,
I'd like to fail sooner.

00:15:25.626 --> 00:15:28.886 align:middle
And the second thing is socketTimeoutMS.

00:15:29.026 --> 00:15:31.556 align:middle
And this defaults to a comically
high 300 seconds.

00:15:31.656 --> 00:15:34.616 align:middle
And this is more because of,
we use the C driver internally.

00:15:34.616 --> 00:15:36.426 align:middle
That's the default.

00:15:37.216 --> 00:15:42.966 align:middle
This is the MongoDB driver's equivalent
to - in php - the default_socket_timeout.

00:15:42.966 --> 00:15:48.016 align:middle
Since our driver no longer uses, originally
we did use php streams internally,

00:15:48.386 --> 00:15:51.756 align:middle
and this did apply, and now
we do the socket IO ourselves.

00:15:51.756 --> 00:15:55.776 align:middle
So now we have our own value for this.

00:15:55.776 --> 00:15:57.986 align:middle
So it is separate from php's
default socket timeout.

00:15:58.086 --> 00:16:01.526 align:middle
But the two things you want to
consider are what is your socket timeout

00:16:01.526 --> 00:16:04.026 align:middle
for other things that you're doing in php.

00:16:04.026 --> 00:16:07.006 align:middle
And then secondly, what is your
script's max execution time.

00:16:07.506 --> 00:16:11.836 align:middle
So on a command line at zero, it will run
forever, which is helpful with a large,

00:16:11.836 --> 00:16:14.496 align:middle
when you're installing things on
composer, it tends to take a while.

00:16:14.806 --> 00:16:18.496 align:middle
And for a web environment, I believe max
execution time is usually 30 seconds,

00:16:18.526 --> 00:16:22.596 align:middle
which is still a long time to service
the request, but you generally don't,

00:16:22.936 --> 00:16:25.346 align:middle
you want this to not exceed
your max_execution_time.

00:16:25.666 --> 00:16:28.426 align:middle
So I would also recommend probably
lowering this to 30 seconds.

00:16:28.426 --> 00:16:34.496 align:middle
And as far as monitoring, and this is the
stuff that's happening in the background,

00:16:34.496 --> 00:16:35.546 align:middle
but you have some control over this.

00:16:36.126 --> 00:16:38.386 align:middle
We can control how frequently
you want monitoring to happen.

00:16:38.716 --> 00:16:43.496 align:middle
So a single-threaded driver, we do
this less frequently, so once a minute,

00:16:43.496 --> 00:16:46.586 align:middle
and we save state between requests.

00:16:46.666 --> 00:16:50.006 align:middle
So if you're serving a quick php request
and you just constructed the driver,

00:16:50.006 --> 00:16:52.926 align:middle
you're not going to hit 60 seconds.

00:16:52.926 --> 00:16:57.996 align:middle
This is more for controlling if your
PHP workers serves hundreds of requests,

00:16:58.216 --> 00:17:01.526 align:middle
maybe 40 or 50 requests down the line,
at some point we're going to realize

00:17:01.526 --> 00:17:05.066 align:middle
that it's been 60 seconds and we
just want to go talk to the servers

00:17:05.066 --> 00:17:10.746 align:middle
and see if we have a good sense, if they're the
same topology that we knew about a minute ago.

00:17:11.776 --> 00:17:15.386 align:middle
And this helps insulate us form errors,
it detects changes if you were to, uh,

00:17:15.646 --> 00:17:18.136 align:middle
one of the benefits of MongoDB
is that you can scale up

00:17:18.136 --> 00:17:19.736 align:middle
and down while your application is running.

00:17:20.136 --> 00:17:23.946 align:middle
So if you were to add more members to
your replica set or the shard cluster,

00:17:23.946 --> 00:17:28.106 align:middle
at the very least, the driver would find
out in 60 seconds, 60 seconds intervals.

00:17:28.426 --> 00:17:31.186 align:middle
And the second is a socket check.

00:17:31.516 --> 00:17:35.466 align:middle
And this is a special thing for
single-threaded drivers as well.

00:17:35.466 --> 00:17:41.076 align:middle
In PHP's case we might have a worker that serves
a php request and then doesn't get used again

00:17:41.076 --> 00:17:43.636 align:middle
for another 30 or maybe five minutes.

00:17:43.726 --> 00:17:45.936 align:middle
Who knows, because you have a pool of workers.

00:17:45.936 --> 00:17:50.906 align:middle
So in this case, before we use a socket,
if it's been longer than five seconds,

00:17:50.906 --> 00:17:52.896 align:middle
we'll just see if it's still valid and that's,

00:17:53.266 --> 00:17:56.776 align:middle
that way we can recover internally before
you get an exception in your application.

00:17:57.616 --> 00:18:03.836 align:middle
These can both be configured if you need to,
but generally these are good as they are.

00:18:04.586 --> 00:18:07.776 align:middle
And the most relevant things to your
application is going to be server selection.

00:18:07.776 --> 00:18:10.546 align:middle
So when the driver tries to
select a server and we see

00:18:10.546 --> 00:18:13.136 align:middle
that happens every time you do an
operation, if you're doing a write,

00:18:13.136 --> 00:18:17.346 align:middle
we're trying to select the primary, the
two main things that you want to focus

00:18:17.346 --> 00:18:20.186 align:middle
on here are the server selection
timeout, and the try once behavior.

00:18:20.906 --> 00:18:27.946 align:middle
And so by default, a threaded driver
will wait up to 30 seconds when it tries

00:18:27.946 --> 00:18:30.376 align:middle
to do an operation because it has
a background thread for monitoring.

00:18:30.736 --> 00:18:32.966 align:middle
If your Java application is
trying to talk to the database,

00:18:33.446 --> 00:18:38.716 align:middle
it will spend up to 30 seconds trying to find
a server to talk to, and that's not as bad

00:18:38.716 --> 00:18:41.676 align:middle
as it sounds because they have their
monitoring constantly in the background

00:18:41.676 --> 00:18:44.386 align:middle
so they very quickly pick up changes
and they have connection pools

00:18:44.386 --> 00:18:46.926 align:middle
so they constantly have available sockets.

00:18:46.926 --> 00:18:50.076 align:middle
And again, php has neither, we have
one connection to a server and we use

00:18:50.076 --> 00:18:53.046 align:middle
that one socket to do both monitoring
and for your application needs.

00:18:53.836 --> 00:18:57.126 align:middle
So therefore, we have a behavior
that allows us to fail fast.

00:18:57.126 --> 00:19:02.156 align:middle
So if we try and talk to a server and it doesn't
exist, we immediately throw an exception.

00:19:02.156 --> 00:19:07.056 align:middle
And the reason we do this is because, consider
the case where we didn't, and we allowed PHP

00:19:07.056 --> 00:19:09.026 align:middle
to block up the 30 seconds looking for a server.

00:19:09.656 --> 00:19:15.596 align:middle
Your php workers would start piling up, opening
more connections and trying to talk to servers

00:19:15.596 --> 00:19:19.716 align:middle
that they can't reach, maybe there was
a fail-over and so there is no primary,

00:19:19.716 --> 00:19:23.056 align:middle
it might take a five or 10 seconds
for a new election to happen

00:19:23.406 --> 00:19:25.786 align:middle
for the database cluster to heal itself.

00:19:26.416 --> 00:19:28.696 align:middle
And meanwhile, you're constantly
opening new php workers.

00:19:28.696 --> 00:19:32.216 align:middle
So your app servers are getting backed up and
you're not serving requests any faster either.

00:19:32.826 --> 00:19:38.236 align:middle
And so the most consistent behavior, even though
it's maybe not the best thing for MongoDB's case

00:19:38.236 --> 00:19:41.376 align:middle
because it can heal itself, the cluster
can heal itself, but because of,

00:19:41.816 --> 00:19:44.216 align:middle
to cater to php's unique needs, it's better

00:19:44.216 --> 00:19:47.096 align:middle
to just throw an exception
immediately as the default behavior.

00:19:47.186 --> 00:19:49.946 align:middle
And so that's the behavior
that we've had historically.

00:19:49.946 --> 00:19:54.366 align:middle
And so we kept it with the newer driver
that we rewrote about three years ago.

00:19:54.916 --> 00:19:59.776 align:middle
Okay, I'm gonna talk a little bit about later
when it turns into deciding how to retry

00:19:59.776 --> 00:20:03.756 align:middle
from errors, we can change that behavior
and how to go about changing that without.

00:20:03.956 --> 00:20:08.086 align:middle
It's not as simple as just
deciding to, say try once false

00:20:08.086 --> 00:20:10.226 align:middle
and then I'll start waiting 30 seconds.

00:20:10.226 --> 00:20:11.846 align:middle
We definitely want to do that intelligently.

00:20:12.396 --> 00:20:14.476 align:middle
Okay. Just do a time check.

00:20:15.456 --> 00:20:16.026 align:middle
Twenty minutes.

00:20:16.126 --> 00:20:16.576 align:middle
Halfway point.

00:20:17.566 --> 00:20:22.296 align:middle
Okay. So some application concepts, before
we get into error handling and transactions.

00:20:22.296 --> 00:20:24.616 align:middle
These are things that...

00:20:24.616 --> 00:20:29.226 align:middle
concepts that the drivers provide
and I don't think they have analogies

00:20:29.226 --> 00:20:34.976 align:middle
in a relational databases, but possibly
other, um, other non-relational databases.

00:20:35.706 --> 00:20:41.926 align:middle
The first is a write concern, and in this
case, ideally a production app is talking

00:20:41.926 --> 00:20:46.896 align:middle
to a replication cluster, so your
data is being written to the primary

00:20:47.276 --> 00:20:50.066 align:middle
and then replicated to the secondary nodes.

00:20:50.186 --> 00:20:53.186 align:middle
And again, to give us insurance
so that if this guy dies,

00:20:53.266 --> 00:20:55.566 align:middle
one of these folks can step
up and be the new primary.

00:20:56.986 --> 00:21:02.016 align:middle
And in some cases they might sync directly from
the primary and in this, yeah, in this case,

00:21:02.016 --> 00:21:04.876 align:middle
they're both reading from the primary,
but they're not all getting the data

00:21:04.876 --> 00:21:09.386 align:middle
at the same time because they basically
tail the activity on the primary.

00:21:09.386 --> 00:21:14.286 align:middle
When you use a write concern and you
issue a write to the database, by default,

00:21:14.486 --> 00:21:16.876 align:middle
we'll send it to the primary and if it succeeds,

00:21:17.126 --> 00:21:19.246 align:middle
the driver gets back control,
you go on and do your business.

00:21:19.556 --> 00:21:21.246 align:middle
And you're not really waiting
for it to replicate.

00:21:22.036 --> 00:21:25.646 align:middle
But ideally, consider the case
where you wrote to the primary

00:21:26.176 --> 00:21:29.976 align:middle
and the data you inserted didn't
get a chance to replicate.

00:21:30.456 --> 00:21:31.436 align:middle
And then the primary died.

00:21:32.016 --> 00:21:34.296 align:middle
From your application's perspective
you think everything's succeeded.

00:21:34.776 --> 00:21:40.046 align:middle
Uh, when in reality it's possible that that
data permanently got destroyed with the primary.

00:21:40.906 --> 00:21:42.816 align:middle
And when one of these secondaries steps up,

00:21:42.816 --> 00:21:46.186 align:middle
the data is basically not there anymore
because it was never replicated.

00:21:47.046 --> 00:21:51.026 align:middle
So the way to control this in an application,
and this is always at the expense of,

00:21:51.026 --> 00:21:54.766 align:middle
if you want more durability in a distributed
system, you're going to wait longer for it.

00:21:55.126 --> 00:21:56.936 align:middle
And so you're gonna decide to use this.

00:21:56.936 --> 00:21:59.066 align:middle
Some things are more important
than other things.

00:21:59.066 --> 00:22:03.016 align:middle
If someone is doing a financial
transaction, you would like to make sure

00:22:03.016 --> 00:22:06.196 align:middle
that the data is persisted and can
survive any kind of disaster scenario.

00:22:06.946 --> 00:22:10.206 align:middle
And so the write concern you would want
to use is just saying I'm concerned

00:22:10.206 --> 00:22:14.216 align:middle
with how this write gets acknowledged in the
system - would be a majority write concern.

00:22:14.416 --> 00:22:18.446 align:middle
And this is a, you can either use a
number, but majority is a nice string

00:22:18.446 --> 00:22:22.656 align:middle
that if you grow your replica
set to seven nodes or 10 nodes,

00:22:22.656 --> 00:22:25.686 align:middle
it's always going to be the
majority number of them, which,

00:22:25.826 --> 00:22:30.616 align:middle
and as long as the majority have acknowledged
the write, it can survive any disaster scenario.

00:22:31.966 --> 00:22:36.436 align:middle
So if we used majority here, the driver would
not get a response until at least one secondary,

00:22:36.436 --> 00:22:38.556 align:middle
at least two nodes have acknowledged the write.

00:22:38.606 --> 00:22:40.446 align:middle
So this is generally what you want to use.

00:22:40.496 --> 00:22:43.176 align:middle
And again, it is a tradeoff:
if you did this for every write

00:22:43.176 --> 00:22:46.346 align:middle
in your application, you're
probably wasting time.

00:22:46.486 --> 00:22:47.926 align:middle
But there's probably some
things in your application

00:22:47.926 --> 00:22:49.116 align:middle
that aren't as important to wait for.

00:22:49.576 --> 00:22:54.636 align:middle
If you're doing a log messages or
small tweets, it's not as important

00:22:54.636 --> 00:22:59.106 align:middle
as someone updating their password or storing
a billing address or something like that.

00:22:59.306 --> 00:23:02.776 align:middle
On the flip side, we have a read concern,
and this is when we're querying the data:

00:23:03.006 --> 00:23:06.816 align:middle
do I just want to go to the primary
and read whatever's available?

00:23:06.816 --> 00:23:08.946 align:middle
Or do I want to make sure that I also read data

00:23:09.096 --> 00:23:12.236 align:middle
that is acknowledged by the
majority of the system?

00:23:12.806 --> 00:23:15.976 align:middle
And so as one applies the writes,
the read concern is obviously going

00:23:15.976 --> 00:23:19.596 align:middle
to make your query slower because maybe
you're waiting for the data to be replicated

00:23:19.596 --> 00:23:26.836 align:middle
or there's, you're going to purposely
read a bit older data that is safe to read

00:23:26.836 --> 00:23:29.796 align:middle
because it exists throughout the
cluster instead of the immediate write

00:23:29.796 --> 00:23:32.956 align:middle
that was just written only to the primary.

00:23:32.956 --> 00:23:36.996 align:middle
So this is a lot to take in, and it's
something to research on your own

00:23:36.996 --> 00:23:38.446 align:middle
and find what works best for your use case.

00:23:38.446 --> 00:23:42.216 align:middle
But I will call out the linearizable.

00:23:42.216 --> 00:23:47.696 align:middle
This was something that was introduced about
two years ago and if anyone is familiar

00:23:48.386 --> 00:23:57.636 align:middle
with the Jepsen tests, which is the call
me maybe distributed database tests, a guy,

00:23:58.146 --> 00:24:05.686 align:middle
Kyle Kingsbury runs a kind of a test framework
for basically experimenting with databases

00:24:05.686 --> 00:24:07.926 align:middle
and finding out all the ways,
how to break them basically.

00:24:08.496 --> 00:24:11.706 align:middle
And so he had tested an older
version of MongoDB years ago.

00:24:11.706 --> 00:24:14.496 align:middle
He's tested many databases over the
years and predictably the older version

00:24:14.496 --> 00:24:16.726 align:middle
of MongoDB did not get a glowing review.

00:24:17.416 --> 00:24:20.946 align:middle
And he found all sorts of ways to break
it and like write to the database and shut

00:24:20.946 --> 00:24:22.846 align:middle
down some nodes and realize
that your data disappeared.

00:24:23.626 --> 00:24:27.586 align:middle
And so this was something that around the time
of Mongo 3.4, which is about two years ago,

00:24:27.586 --> 00:24:31.156 align:middle
they put a lot of effort into addressing and
making sure that we can pass that test suite.

00:24:31.526 --> 00:24:35.556 align:middle
And now that, his test framework
is now part of our CI system.

00:24:36.066 --> 00:24:40.136 align:middle
So versions since 3.4 have
been able to satisfy this.

00:24:40.586 --> 00:24:44.736 align:middle
This is important maybe to
people on hacker news.

00:24:44.736 --> 00:24:47.916 align:middle
As for everyone's, for your individual app,

00:24:48.076 --> 00:24:50.686 align:middle
does every individual app need
these kinds of guarantees?

00:24:50.686 --> 00:24:55.766 align:middle
Of linearizability basically being able
to, everything you write and being able

00:24:55.766 --> 00:25:01.256 align:middle
to read it back immediately, and
having those very strong guarantees?

00:25:01.576 --> 00:25:02.506 align:middle
Not for every use case.

00:25:02.656 --> 00:25:06.556 align:middle
But the functionality is there if you
need it, and it goes without saying

00:25:06.556 --> 00:25:10.766 align:middle
that the more guarantees you get, these
are going to be slower than just reading,

00:25:11.066 --> 00:25:14.836 align:middle
local is basically just reading
whatever the primary has for you.

00:25:14.946 --> 00:25:17.836 align:middle
But know that those exist and when
you need those extra guarantees,

00:25:18.176 --> 00:25:19.986 align:middle
there is functionality available to obtain them.

00:25:19.986 --> 00:25:26.476 align:middle
And so because these things tend to take
longer, I advise not to use socket timeouts.

00:25:26.526 --> 00:25:28.526 align:middle
We don't want to leave...

00:25:28.526 --> 00:25:31.196 align:middle
using socket timeouts as a
way to abandon operations

00:25:31.196 --> 00:25:35.716 align:middle
on a remote database is probably a
bad idea, whether it's MongoDB or SQL.

00:25:35.716 --> 00:25:39.646 align:middle
If you start a long query and the
driver just goes away and ignores it.

00:25:39.926 --> 00:25:43.016 align:middle
You're letting something continue to run
on the database and now it's basically kind

00:25:43.016 --> 00:25:45.416 align:middle
of a Zombie process until
the database server realizes

00:25:45.416 --> 00:25:47.766 align:middle
that no one's ever going
to get the result for that.

00:25:48.396 --> 00:25:51.536 align:middle
So we really don't want to use socket
timeouts to limit our operations.

00:25:51.966 --> 00:25:53.326 align:middle
MongoDB provides...

00:25:53.326 --> 00:25:56.626 align:middle
all the operations that talk to a
database, you can specify a time.

00:25:57.116 --> 00:25:59.786 align:middle
And this basically corresponds to CPU time

00:25:59.786 --> 00:26:03.456 align:middle
that the server will kill the
operation if it goes too far.

00:26:03.536 --> 00:26:05.626 align:middle
And now this is, socket timeouts are exact.

00:26:05.626 --> 00:26:10.116 align:middle
If you tell your drivers, say I want to give
up after 10 seconds, it's exactly 10 seconds

00:26:10.116 --> 00:26:13.276 align:middle
for the, on the client side,
whereas maxTimeMS is a bit softer.

00:26:13.276 --> 00:26:18.006 align:middle
It's saying that I'm allowing this to run for 10
seconds of processing time on the remote side.

00:26:18.636 --> 00:26:22.226 align:middle
So this may end around 11 seconds or 12 seconds.

00:26:22.486 --> 00:26:25.306 align:middle
So you don't want to set this exactly
to whatever your socket timeout is.

00:26:25.366 --> 00:26:28.066 align:middle
But if you have long running
operations, this will ensure that you

00:26:28.066 --> 00:26:30.956 align:middle
at least also don't leave them,
even if the client does give up,

00:26:31.056 --> 00:26:34.156 align:middle
you don't leave them running on the remote side.

00:26:34.156 --> 00:26:37.966 align:middle
And so this you can apply to reads and
writes, but for write concerns I mentioned

00:26:37.966 --> 00:26:42.246 align:middle
when you're waiting for replication, in
that case, just to take us back to this,

00:26:42.566 --> 00:26:45.096 align:middle
this "Apply" step is the operation succeeding.

00:26:45.096 --> 00:26:46.246 align:middle
So this would be your maxTimeMS.

00:26:46.866 --> 00:26:50.506 align:middle
But then waiting for the replication
to happen is a whole separate thing.

00:26:50.506 --> 00:26:52.666 align:middle
That's the operation succeeded,
but you're still,

00:26:52.736 --> 00:26:55.326 align:middle
just going to wait before
it returns to the driver.

00:26:55.766 --> 00:26:57.416 align:middle
So that's known as a wTimeout.

00:26:57.416 --> 00:26:58.826 align:middle
And that's another thing you can say:

00:26:58.826 --> 00:27:01.266 align:middle
if you're using the majority write
concern, you might want to...

00:27:01.266 --> 00:27:05.146 align:middle
you know, that your writes are going
to be quick, but you also don't want

00:27:05.146 --> 00:27:08.136 align:middle
to wait forever for replication to happen.

00:27:08.136 --> 00:27:12.236 align:middle
And so in this case, you will be able to
distinguish: did my write actually succeed?

00:27:12.236 --> 00:27:14.546 align:middle
So I inserted successfully,
there was no duplicate key error.

00:27:15.016 --> 00:27:18.006 align:middle
But at the same token, we timed
out waiting for replication.

00:27:18.126 --> 00:27:21.886 align:middle
Does that mean that my write
didn't succeed at all?

00:27:21.886 --> 00:27:26.066 align:middle
No, it succeeded, but you're not guaranteed
at that moment that it had replicated.

00:27:26.066 --> 00:27:30.136 align:middle
It's probably still going to
replicate if nothing, no servers died.

00:27:30.346 --> 00:27:34.586 align:middle
So this is, we might, you might call this
a soft error instead of a harder error

00:27:34.586 --> 00:27:35.646 align:middle
of the data actually not entering.

00:27:36.016 --> 00:27:38.526 align:middle
You have a message?

00:27:39.096 --> 00:27:47.626 align:middle
A causal consistency, a causal consistency is
basically being able to read your own writes

00:27:47.626 --> 00:27:50.836 align:middle
if you write something, there's
like a linear progression of data.

00:27:50.836 --> 00:27:54.826 align:middle
So if you write to the database, being able to
read your stuff back of the previous operation.

00:27:54.826 --> 00:27:56.906 align:middle
So there's an ordering component to that.

00:27:57.886 --> 00:28:01.056 align:middle
So whenever an operation logically
depends on the thing before,

00:28:01.056 --> 00:28:04.246 align:middle
there's a causal relationship for it.

00:28:04.246 --> 00:28:07.786 align:middle
And so the different guarantees there, one is
being able to read your own writes, which is,

00:28:08.066 --> 00:28:09.346 align:middle
and when you have a standalone system

00:28:09.346 --> 00:28:11.736 align:middle
where it's just one database
server, you implicitly have this.

00:28:11.736 --> 00:28:15.726 align:middle
But when we add distributed nodes and there's
replication and things like happening,

00:28:16.496 --> 00:28:20.666 align:middle
it gets a lot more complicated to make these
guarantees and that's when things get slower.

00:28:21.146 --> 00:28:23.396 align:middle
So in a replica set, the idea

00:28:23.396 --> 00:28:26.756 align:middle
of causal consistency is not only reading
own writes, but they're monotonic.

00:28:26.966 --> 00:28:30.706 align:middle
So that means if they get applied
in the order that they are executed

00:28:30.706 --> 00:28:33.286 align:middle
by the driver, writes follow reads.

00:28:33.356 --> 00:28:39.536 align:middle
So if you were to read some data and then write,
do write after that, that write is being applied

00:28:39.536 --> 00:28:43.446 align:middle
to the same data on the database side that
you had previously read in the driver.

00:28:43.446 --> 00:28:46.056 align:middle
So just, logically, this is
how we expect things to work.

00:28:46.286 --> 00:28:52.856 align:middle
So it doesn't take, it's not hard to grasp
what this is, but it's something I think of,

00:28:52.856 --> 00:28:56.366 align:middle
we take this for granted
basically when we're working

00:28:56.366 --> 00:29:01.346 align:middle
with standalone databases
where there's only one node.

00:29:01.346 --> 00:29:03.636 align:middle
And so this, there's majority
read and write concerns.

00:29:03.636 --> 00:29:06.836 align:middle
This basically can be satisfied by using those.

00:29:07.176 --> 00:29:11.446 align:middle
And durability is the idea that when I write
something it will survive: it's durable

00:29:11.446 --> 00:29:14.426 align:middle
and that it will survive if we pull the
plug on the primary, it's been replicated.

00:29:14.596 --> 00:29:16.196 align:middle
So it's durable: can survive an error.

00:29:16.686 --> 00:29:20.246 align:middle
And in your application,
we can make use of this.

00:29:20.286 --> 00:29:22.276 align:middle
The driver provides a session object.

00:29:22.276 --> 00:29:26.106 align:middle
We can pass this around to operations and this
provides this functionality if you need it.

00:29:26.496 --> 00:29:28.806 align:middle
There's plenty of examples for that.

00:29:29.396 --> 00:29:30.326 align:middle
So I mentioned sessions.

00:29:30.326 --> 00:29:34.346 align:middle
This is a relatively new feature
within the last year or so.

00:29:34.346 --> 00:29:35.106 align:middle
Sessions are a way...

00:29:35.106 --> 00:29:37.876 align:middle
so previously operations in
MongoDB were tied to the connection.

00:29:38.056 --> 00:29:42.246 align:middle
And so once we lose the connection, the server
has no, doesn't remember us at all, that's our,

00:29:42.246 --> 00:29:45.906 align:middle
the queries that were running or any writes
that we did, they were tied to our connection.

00:29:46.766 --> 00:29:50.566 align:middle
Assuming they didn't, if they made it,
if they were applied, that's different.

00:29:50.876 --> 00:29:53.726 align:middle
But if any state that we
had about who was connecting

00:29:53.726 --> 00:29:55.116 align:middle
to us was only based on the connection.

00:29:55.546 --> 00:29:57.766 align:middle
So sessions allow us - much like php sessions -

00:29:58.186 --> 00:30:00.876 align:middle
give us some state beyond just
connecting to the database.

00:30:01.926 --> 00:30:04.966 align:middle
And so sessions we can be,
we can create them explicitly

00:30:04.966 --> 00:30:06.426 align:middle
and we can pass them around to operations.

00:30:06.926 --> 00:30:12.676 align:middle
Internally, the driver also, anything we talk to
the server now, if it's a new enough MongoDB 3.6

00:30:12.676 --> 00:30:15.386 align:middle
or later, we're going to send a session
with it and make sure every operation

00:30:15.386 --> 00:30:16.896 align:middle
that we execute is tied to some session.

00:30:17.336 --> 00:30:21.336 align:middle
That gives us an extra way to,
uh, as a system administrator,

00:30:21.336 --> 00:30:23.876 align:middle
to monitor operations that are long running.

00:30:24.326 --> 00:30:27.636 align:middle
We can, instead of just having to,
instead of getting orphan things, we can,

00:30:27.866 --> 00:30:30.746 align:middle
the server keeps track of sessions
and they can be cleaned up,

00:30:30.866 --> 00:30:32.816 align:middle
clean up like Zombie queries
and things like that.

00:30:33.616 --> 00:30:37.816 align:middle
And then this plays into
our ability to retry things.

00:30:37.846 --> 00:30:41.676 align:middle
And so, another quick time
check 10 minutes remaining.

00:30:42.266 --> 00:30:45.956 align:middle
So this was something that I pulled out
of an old version of Doctrine MongoDB.

00:30:45.956 --> 00:30:47.176 align:middle
Please don't do this.

00:30:47.176 --> 00:30:48.636 align:middle
This is just the retry loop.

00:30:48.786 --> 00:30:52.876 align:middle
It takes the closure, how many times you
want to retry it and will continually try

00:30:52.876 --> 00:30:55.616 align:middle
to call the closure until it
doesn't throw an exception.

00:30:56.296 --> 00:31:02.366 align:middle
So I assure you Doctrine MongoDB has never,
the ODM has never used this for writing.

00:31:02.966 --> 00:31:05.126 align:middle
It's used this for opening
connections and doing queries.

00:31:05.616 --> 00:31:08.646 align:middle
But that's still bad because if you're
doing queries, we really don't know

00:31:08.646 --> 00:31:10.136 align:middle
if the query is still running on the server.

00:31:10.326 --> 00:31:12.566 align:middle
So this doesn't exist anymore.

00:31:12.566 --> 00:31:14.886 align:middle
I think it was deleted.

00:31:15.116 --> 00:31:16.866 align:middle
But what's the problem with retrying anything?

00:31:16.896 --> 00:31:19.076 align:middle
We get an exception, why don't we just retry it?

00:31:19.076 --> 00:31:21.266 align:middle
And this is something you
can apply to any database.

00:31:21.916 --> 00:31:24.516 align:middle
So we have to be aware that
read and write operations,

00:31:24.516 --> 00:31:26.596 align:middle
they can change the state of the system.

00:31:26.596 --> 00:31:28.526 align:middle
So read can leave the query...

00:31:28.526 --> 00:31:31.466 align:middle
I mentioned if you have a socket timeout
of like five seconds you start query,

00:31:31.466 --> 00:31:33.436 align:middle
that's going to take five minutes to run, right?

00:31:33.436 --> 00:31:39.246 align:middle
The driver gives up, it goes on and does other
things in php land, but the server, it says:

00:31:39.246 --> 00:31:41.936 align:middle
"oh, I'm gonna work on this hard
for you for next five minutes

00:31:41.936 --> 00:31:43.176 align:middle
because you really need this response".

00:31:43.176 --> 00:31:46.326 align:middle
And then by the time it tries to give it to
you, it realizes, oh, that bastard went away.

00:31:46.976 --> 00:31:49.526 align:middle
And that's just a query case.

00:31:49.526 --> 00:31:53.006 align:middle
In a write case it's kind of more dangerous:
instead of just wasting resources on the server,

00:31:53.396 --> 00:31:57.156 align:middle
a write operation, if it's not idempotent, which
means we can't safely run it multiple times,

00:31:57.686 --> 00:32:00.796 align:middle
we have the risk of, think of a write
operation that does an increment.

00:32:00.796 --> 00:32:02.876 align:middle
It maybe, it's an innocuous,
it's not really a problem,

00:32:02.876 --> 00:32:05.566 align:middle
but if you were to just retry
the increment operation,

00:32:05.886 --> 00:32:08.616 align:middle
you don't know if you're accidentally
over counting or under counting.

00:32:09.916 --> 00:32:16.626 align:middle
So at best we're wasting time and resources,
at worst we're making the data inaccurate.

00:32:16.846 --> 00:32:20.196 align:middle
So we want to really think
about how we approach this.

00:32:20.476 --> 00:32:25.016 align:middle
So the different kind of errors, first
you want to ask before we decide to retry:

00:32:25.016 --> 00:32:27.206 align:middle
what are the kinds of errors
that we're trying to address?

00:32:27.516 --> 00:32:29.896 align:middle
So I think there's three types of
errors and one is a transient error.

00:32:29.896 --> 00:32:33.776 align:middle
I think of that as: we dropped the
network connection or the primary stepped

00:32:33.776 --> 00:32:36.556 align:middle
down because it was under
maintenance and a secondary stepped up.

00:32:36.956 --> 00:32:38.756 align:middle
This is a kind of a self-healing scenario,

00:32:38.756 --> 00:32:40.656 align:middle
it will resolve itself if
we try it again, probably.

00:32:41.356 --> 00:32:44.296 align:middle
Then there's a persistent outage, which
is like the whole data center shut down,

00:32:44.616 --> 00:32:46.186 align:middle
but you really can't do anything about that.

00:32:46.726 --> 00:32:50.426 align:middle
But we really can't, we don't know
the difference between these until we

00:32:50.426 --> 00:32:52.356 align:middle
at least try maybe once or twice.

00:32:52.846 --> 00:32:55.146 align:middle
And if we retry and there's no changes,

00:32:55.146 --> 00:32:58.616 align:middle
we can assume that what we thought was a
transient error is probably a persistent outage.

00:32:59.126 --> 00:33:00.406 align:middle
And lastly, there's a command error.

00:33:00.406 --> 00:33:03.966 align:middle
This is: we did something, the database
came back to us with a result and said,

00:33:04.236 --> 00:33:05.286 align:middle
you're an idiot, you did this wrong.

00:33:05.686 --> 00:33:09.696 align:middle
So in that case, if you're trying to insert
something and it says your command is malformed,

00:33:09.696 --> 00:33:12.546 align:middle
you don't want to retry the command, you're
probably gonna get the same response.

00:33:12.716 --> 00:33:16.506 align:middle
In fact, I think the definition of
insanity would be retrying in that case

00:33:16.506 --> 00:33:17.526 align:middle
and expecting a different result.

00:33:18.266 --> 00:33:21.806 align:middle
So those are your three types of errors
and what we really want to optimize for -

00:33:21.806 --> 00:33:25.466 align:middle
we really can't do anything about
this - this is either change the code

00:33:25.796 --> 00:33:27.796 align:middle
or actually this is an error for the user.

00:33:29.126 --> 00:33:32.956 align:middle
Persistent outage, we probably, maybe
someone will get a page and they'll fix it,

00:33:32.956 --> 00:33:35.726 align:middle
but our application probably can't
do anything about that either.

00:33:35.726 --> 00:33:37.926 align:middle
But we can optimize for this:
this is really the case,

00:33:37.926 --> 00:33:40.596 align:middle
the transient errors, what we want to handle.

00:33:40.596 --> 00:33:44.606 align:middle
So retryable errors is either gonna be a network
error or maybe a response from the server

00:33:44.606 --> 00:33:46.486 align:middle
that indicates that it's a transient error.

00:33:46.486 --> 00:33:52.376 align:middle
So, if the primary was coming down for
maintenance, it might be totally offline -

00:33:52.466 --> 00:33:56.446 align:middle
we got a network error - or it might be
alive for a bit and realizing that, Hey,

00:33:56.446 --> 00:34:00.886 align:middle
I'm shutting down, here's a response and I'm
telling you that I'm no longer the primary.

00:34:00.886 --> 00:34:01.896 align:middle
And so those are two cases.

00:34:01.896 --> 00:34:06.006 align:middle
This is usually caused by, there's maintenance
or there's a failover happening and we managed

00:34:06.006 --> 00:34:09.526 align:middle
to talk to the server before they,
before they totally disappeared.

00:34:10.416 --> 00:34:13.336 align:middle
But this is probably the most common one:
it's just going to be the network error.

00:34:13.336 --> 00:34:14.516 align:middle
This is more of a timing coincidence.

00:34:14.836 --> 00:34:18.736 align:middle
And so from a retrying reads, I'd say we want

00:34:18.926 --> 00:34:21.666 align:middle
to avoid leaving long-running
things running on the server.

00:34:21.856 --> 00:34:24.886 align:middle
So queries that return a single
doc if you're just querying by id

00:34:24.886 --> 00:34:27.246 align:middle
or a single response, you
can retry those, right?

00:34:27.246 --> 00:34:29.516 align:middle
Those aren't very expensive queries.

00:34:29.516 --> 00:34:33.076 align:middle
If you know, it's a short run query,
and this is your personal use case

00:34:33.076 --> 00:34:35.756 align:middle
and maybe you're just returning
one batch of documents or you know,

00:34:35.756 --> 00:34:38.386 align:middle
it's gonna just run for maybe a second or two.

00:34:38.856 --> 00:34:40.216 align:middle
Those may be safe to retry.

00:34:40.486 --> 00:34:46.016 align:middle
And as of MongoDB 4.2, which will be coming out
later in the year, the driver is going to try

00:34:46.016 --> 00:34:49.196 align:middle
to automatically retry operations,
any kind of read operation,

00:34:49.286 --> 00:34:50.446 align:middle
even if it's a long running query.

00:34:51.076 --> 00:34:55.206 align:middle
And this is because these server will
have now functionalities that, you know,

00:34:55.206 --> 00:34:57.396 align:middle
the connection was abandoned
so I can abort the operation.

00:34:57.516 --> 00:34:59.316 align:middle
So this kind of addresses the, we're going

00:34:59.316 --> 00:35:01.876 align:middle
to leave some long running operation
accidentally running - the queries are going

00:35:01.876 --> 00:35:03.466 align:middle
to churn for five minutes while we gave up.

00:35:04.106 --> 00:35:05.056 align:middle
So that'll avoid that.

00:35:05.496 --> 00:35:09.066 align:middle
What we still can't do is if you're
iterating a large batch on an existing query,

00:35:09.066 --> 00:35:11.136 align:middle
what we do getMore() is when
you iterate on your results.

00:35:11.136 --> 00:35:16.046 align:middle
We can't retry that because those are
forward-only iteration, so that doesn't work.

00:35:16.046 --> 00:35:19.196 align:middle
But the initial find command or the
aggregate command, we can retry that.

00:35:20.426 --> 00:35:24.706 align:middle
And now writes are a bit more complicated
because not all writes are idempotent.

00:35:25.226 --> 00:35:30.436 align:middle
But given a few things, so sessions are
cluster-wide, so they, I mentioned that before,

00:35:30.956 --> 00:35:34.526 align:middle
uh, they keep track of our state
long after our connection dies.

00:35:35.516 --> 00:35:38.546 align:middle
Every operation is associated with a
session and we can also give it an id,

00:35:38.546 --> 00:35:41.526 align:middle
which I'm just inventing
now, just trust me, this is,

00:35:41.526 --> 00:35:45.546 align:middle
we're just every session we'll just have,
the driver will increment some id value just

00:35:45.546 --> 00:35:47.206 align:middle
so we can uniquely identify everything.

00:35:48.086 --> 00:35:51.316 align:middle
And then we also already have monitoring
and server selection I talked about.

00:35:51.316 --> 00:35:52.656 align:middle
So we can rely on monitoring.

00:35:53.016 --> 00:35:56.916 align:middle
If the primary disappears, we can go back
to monitoring and say I need a new primary.

00:35:57.966 --> 00:36:03.596 align:middle
So we can rely on safely retrying things, so
if you're doing updating a single document,

00:36:03.596 --> 00:36:07.616 align:middle
inserting a single document, or doing a
batch of those operations, they're all,

00:36:07.616 --> 00:36:11.326 align:middle
each one is uniquely identified and we can
continually send them to the server and trust it

00:36:11.326 --> 00:36:14.986 align:middle
to do the right thing, which means
since they're all uniquely identified,

00:36:15.416 --> 00:36:17.926 align:middle
if the server gets the write and
realizes: "Hey, I never applied this",

00:36:17.926 --> 00:36:19.516 align:middle
it's going to do it and return the result.

00:36:19.976 --> 00:36:24.346 align:middle
And if it already applied it, it knows that
it did so and it's going to return the result

00:36:24.346 --> 00:36:27.356 align:middle
that we didn't get the first time,
maybe because there was a network error.

00:36:28.026 --> 00:36:31.746 align:middle
So this basically gives us a safe way to do
stuff and we like to call this at most once a.

00:36:32.226 --> 00:36:37.056 align:middle
So any of the write that we retry, we want them
to happen at most once and because at most once

00:36:37.056 --> 00:36:39.126 align:middle
that might be zero times if
there is a persistent failure

00:36:39.126 --> 00:36:40.516 align:middle
and we just can't talk to the server.

00:36:40.806 --> 00:36:48.516 align:middle
And so this really wants, again in php, the try
once, doesn't work with try once because we want

00:36:48.566 --> 00:36:50.816 align:middle
to actively monitor the server for a loop.

00:36:50.816 --> 00:36:55.456 align:middle
So because we want to talk to the server,
the default behavior would just give

00:36:55.456 --> 00:36:58.456 align:middle
up if we can't find a primary
because php wants to fail fast,

00:36:58.786 --> 00:37:00.896 align:middle
it's not going to wait a few
seconds for an election to happen

00:37:01.126 --> 00:37:02.256 align:middle
and for a new primary to step up.

00:37:02.906 --> 00:37:05.756 align:middle
So to really make good use of
retryable writes, we want to enable,

00:37:05.756 --> 00:37:09.216 align:middle
we want to disable the try
once behavior in your write.

00:37:10.236 --> 00:37:13.566 align:middle
And there's a link here, of a gist
where I demonstrate how to do this.

00:37:13.566 --> 00:37:18.266 align:middle
And I also tuned the timeout value
down from 30 seconds a bit lower.

00:37:18.676 --> 00:37:22.396 align:middle
And this is basically our
user Atlas cloud service.

00:37:22.776 --> 00:37:27.706 align:middle
I keep spamming update statements to it and I
initiate a failover and take the primary down

00:37:28.076 --> 00:37:31.016 align:middle
and if you could watch the logs of the
script, it doesn't generate any errors.

00:37:31.356 --> 00:37:35.956 align:middle
When the primary comes down it certainly waits
about eight or nine seconds for the election

00:37:35.956 --> 00:37:39.056 align:middle
to happen, but if you want your app
totally insulated from errors that,

00:37:39.056 --> 00:37:42.606 align:middle
in that case we can avoid exceptions
entirely, which is really nice.

00:37:42.606 --> 00:37:46.966 align:middle
In Doctrine, in ODM's case, most of all the
updates it does, it doesn't do updateMany,

00:37:47.176 --> 00:37:54.186 align:middle
so this is a great use case for Doctrine
to take advantage of retryable writes.

00:37:54.186 --> 00:37:55.336 align:middle
Okay. 60% of the time...

00:37:55.336 --> 00:37:56.696 align:middle
it works every time.

00:37:56.696 --> 00:38:02.766 align:middle
Generally it's going to improve things, but
again, it's, we can't resolve the other...

00:38:02.766 --> 00:38:07.776 align:middle
it's about transient errors, it's not about the
other important things that we can't change.

00:38:08.256 --> 00:38:11.736 align:middle
So lastly, I'm a little bit over time,
I'll try and do this in three minutes.

00:38:11.736 --> 00:38:15.966 align:middle
Transactions, this is our actually
ACID compliant transactions.

00:38:16.016 --> 00:38:20.576 align:middle
And so getting to this point, goes back a
number of years and adding features slowly

00:38:20.576 --> 00:38:24.806 align:middle
to the database and ultimately sessions,
and then 4.0 is the most recent release

00:38:25.106 --> 00:38:26.796 align:middle
with transactions on replica sets.

00:38:26.876 --> 00:38:29.616 align:middle
And then in the summer it will be
transactions on shard clusters.

00:38:30.116 --> 00:38:34.636 align:middle
I cannot emphasize the complexity involved
with transactions on shard clusters.

00:38:34.636 --> 00:38:38.356 align:middle
Replica sets is a bit easier, but I
don't, this is above my pay grade.

00:38:39.316 --> 00:38:44.116 align:middle
So transactions at a glance,
when we do a transaction,

00:38:44.156 --> 00:38:46.666 align:middle
you're probably doing a transaction
because of writes.

00:38:46.666 --> 00:38:50.256 align:middle
So the entire transaction has to go to the
same node and because it's a transaction

00:38:50.256 --> 00:38:53.046 align:middle
and you're probably doing writes, that means
the primary, it doesn't really make sense

00:38:53.046 --> 00:38:54.226 align:middle
to do a transaction with just reads.

00:38:55.006 --> 00:38:57.706 align:middle
Your read and write concern
instead of per-operation,

00:38:57.706 --> 00:38:59.156 align:middle
you do that for the entire transaction.

00:38:59.416 --> 00:39:03.246 align:middle
So everything has to have the same
level of guarantees around it.

00:39:03.486 --> 00:39:06.296 align:middle
And that's important to the concept of a
transaction because it's either all going

00:39:06.296 --> 00:39:07.546 align:middle
to work or it's, none of it's going to work.

00:39:08.296 --> 00:39:11.036 align:middle
And while you can do many operations
there are some things you can't do,

00:39:11.036 --> 00:39:16.136 align:middle
you can't create collections or drop tables.

00:39:16.246 --> 00:39:20.056 align:middle
But all your basic crud operations,
your aggregation frameworks and stuff,

00:39:20.056 --> 00:39:22.486 align:middle
you can certainly, those are
all supported intentionally

00:39:22.486 --> 00:39:24.826 align:middle
because that's the common use case.

00:39:24.996 --> 00:39:29.006 align:middle
So in php it looks pretty straightforward
and I'm not using custom write concerns

00:39:29.006 --> 00:39:30.256 align:middle
or read concerns here to keep it simple.

00:39:30.256 --> 00:39:33.016 align:middle
But from our client, we can
make a session object

00:39:33.556 --> 00:39:35.816 align:middle
and that's our gateway to
start and commit things.

00:39:36.226 --> 00:39:39.046 align:middle
And you want to make sure you pass
your session to all the operations.

00:39:39.306 --> 00:39:42.266 align:middle
If I forgot the pass this here, then
this insertOne() is not associated

00:39:42.266 --> 00:39:44.766 align:middle
with the transaction it's actually
just going to run immediately.

00:39:45.346 --> 00:39:50.186 align:middle
So that's kind of , there's not really,
we don't have like SQL grammar here.

00:39:50.296 --> 00:39:55.036 align:middle
So the API relies on you passing
around the session to every operation.

00:39:55.306 --> 00:39:56.796 align:middle
And similar, if you're doing causal consistency,

00:39:56.796 --> 00:39:59.446 align:middle
you want to associate your
operations with sessions.

00:40:00.126 --> 00:40:04.526 align:middle
So for transactions you're definitely gonna use
explicit sessions and pass that option around.

00:40:05.216 --> 00:40:07.576 align:middle
And now the important thing is
transactions can be retried.

00:40:07.926 --> 00:40:13.676 align:middle
And so, the driver is able, if a commit or an
abort command fails because of a socket error,

00:40:13.676 --> 00:40:17.996 align:middle
we can retry that, and we'll do that for
you once, just to try and insulate you.

00:40:17.996 --> 00:40:20.426 align:middle
And if there's a quick error
that we can recover from, great.

00:40:21.196 --> 00:40:24.976 align:middle
Uh, if you want, you can retry
committing more times if you want.

00:40:24.976 --> 00:40:30.246 align:middle
If you want to do that in a loop until
it succeeds or retry any number of times.

00:40:30.246 --> 00:40:34.316 align:middle
We don't bother retrying other operations that's
left to you to decide if you want to do that.

00:40:34.986 --> 00:40:36.456 align:middle
And the other important thing is transactions

00:40:36.456 --> 00:40:38.366 align:middle
and retryable writes are two
completely separate things.

00:40:38.366 --> 00:40:41.536 align:middle
So retryable writes was implemented
first and that's meant to be used -

00:40:42.116 --> 00:40:43.826 align:middle
you can throw that into any
application and kind of,

00:40:43.826 --> 00:40:46.366 align:middle
it just works for a lot of your write activity.

00:40:46.556 --> 00:40:51.146 align:middle
Transactions are something you're opting into
and the transactions were really the main idea

00:40:51.146 --> 00:40:52.606 align:middle
that the main goal that we had to get to,

00:40:52.726 --> 00:40:55.036 align:middle
and retryable writes was something
quickly we were able to do along the way.

00:40:56.276 --> 00:40:59.496 align:middle
Uh, so keep in mind that,
they are separate concepts

00:40:59.496 --> 00:41:02.926 align:middle
that are mutually exclusive even though they
kind of use the same internal machinery.

00:41:03.776 --> 00:41:06.356 align:middle
But the important thing is if
the entire transaction fails

00:41:06.356 --> 00:41:09.306 align:middle
or if an operation inside the
transaction fails, you can restart.

00:41:09.306 --> 00:41:10.856 align:middle
You can restart the transaction
from the beginning.

00:41:11.276 --> 00:41:16.386 align:middle
So if we were doing a transaction and say this
second insert failed, I can catch that exception

00:41:16.386 --> 00:41:17.686 align:middle
and then try and restart the whole thing.

00:41:17.686 --> 00:41:23.346 align:middle
And so the important thing you want to do
here is probably have your stuff in a closure

00:41:23.476 --> 00:41:26.946 align:middle
or a function call that you can call
and wrap with a start and commit.

00:41:27.366 --> 00:41:32.196 align:middle
So you can catch an exception and you can
retry quite easily, or do a while loop

00:41:32.196 --> 00:41:34.176 align:middle
if you really like the procedural style.

00:41:35.006 --> 00:41:36.216 align:middle
So knowing when to retry.

00:41:36.446 --> 00:41:38.886 align:middle
Our exceptions in the driver,
there's two different labels.

00:41:38.986 --> 00:41:42.896 align:middle
Why not? Gruber seems to agree with me.

00:41:43.246 --> 00:41:49.426 align:middle
So transaction errors, we need a way to
highlight errors from the driver and know

00:41:49.706 --> 00:41:52.066 align:middle
with more than just the exception
message or code.

00:41:52.596 --> 00:41:58.076 align:middle
So having a label, um, there's two labels
out of the gate and one of them, this is,

00:41:58.076 --> 00:42:01.406 align:middle
if an exception is thrown
during a commit, the exception,

00:42:01.406 --> 00:42:03.666 align:middle
having this label tells you
that you can retry the commit.

00:42:04.546 --> 00:42:09.526 align:middle
And this is a label that you might get
on any runtime exception in your code.

00:42:09.526 --> 00:42:11.836 align:middle
So those insert ones might throw
an exception with this label

00:42:12.136 --> 00:42:17.496 align:middle
and that means things have failed and if you
want to retry it, start from the top again

00:42:17.496 --> 00:42:21.906 align:middle
and start from, start transaction and try
and go through the whole process again.

00:42:21.906 --> 00:42:23.146 align:middle
There's examples of how to do this.

00:42:23.146 --> 00:42:24.046 align:middle
It's very hairy.

00:42:24.096 --> 00:42:28.056 align:middle
So something that we're trying to do in the
next few months is have a convenience methods

00:42:28.056 --> 00:42:30.356 align:middle
so that you just give us
a closure and we'll run it

00:42:30.406 --> 00:42:32.156 align:middle
and do all the try catching
and retrying for you.

00:42:32.426 --> 00:42:38.616 align:middle
But if you want to wrap your head around the
annoying try-catch nonsense that you have to do,

00:42:38.796 --> 00:42:42.216 align:middle
for handling this, you can take a look
at the documentation currently has that

00:42:42.216 --> 00:42:45.246 align:middle
and we're going to adapt it to a better API.

00:42:46.596 --> 00:42:48.876 align:middle
Alright. So these are some resources.

00:42:48.876 --> 00:42:49.776 align:middle
I will share the slides.

00:42:49.776 --> 00:42:54.426 align:middle
This was an older presentation I did, just on
if you want to know about retryable writes.

00:42:54.426 --> 00:42:56.236 align:middle
There's a lot of good diagrams
and stuff in here.

00:42:56.236 --> 00:43:00.896 align:middle
This is a lot of relevant documentation you'll
want to read up on the subjects we talked about.

00:43:00.896 --> 00:43:04.896 align:middle
And this is my coworker's presentation from
many years ago before we had retryable writes.

00:43:05.346 --> 00:43:10.076 align:middle
So if you're using MongoDB 2.4 for some
reason and you want to retry write operations,

00:43:10.076 --> 00:43:13.556 align:middle
he has an approach for what you can
retry and how to do so responsibly.

00:43:14.266 --> 00:43:14.946 align:middle
Thank you.

00:43:15.186 --> 00:43:16.516 align:middle
Please leave me some feedback later.

00:43:16.516 --> 00:43:21.386 align:middle
I'll see you all tonight for jeopardy and
I'll stand outside for questions after.

00:43:28.986 --> 00:43:33.016 align:middle
Thank you for your laptop.

