LongCut logo

Getting to know Temporal

By Temporal

Summary

Topics Covered

  • Microservices Complexity Explodes
  • Temporal Abstracts Chaos Away
  • 15 Years Refines Right Abstraction
  • Durable Execution Survives Failures
  • Taco Orders Demand Durable Scale

Full Transcript

[Music] hello and welcome to this session uh we're really excited to have you here today what we want to provide is really

a basic Foundation understanding of of temporal the technology and how it's used in in with bi-developers across lots of you know leading organizations all over the whole planet um

I'm joined today my name is Jim Walker I'm the VP of product marketing here at temporal and I'm joined today by two my esteemed colleagues that I'm going to let them introduce themselves so max let's start with you I'm Maxim I'm a

co-founder of temporal project and now I'm with CEO in of the company that's right my ultimate boss that's right in Ryland uh I'm Rylan Goldstein I'm the head of

product here at temporal and I'm an early employee of the company yeah I mean how long have you been at temporal Ryland uh like three and a half years a lifetime a lifetime and portal terms for sure so between the two of you I think

we have more knowledge than almost on the planet around temporal uh well there's a there's a couple other people that have a lot of really great knowledge um what we'd like to do is just run through a couple just a baseline understanding of kind of where

it fits we'll talk a little bit about the history of the project and how how Max started and and doing all this work and then a little bit about some customers um so just to get started

um you know as as application Architects and as developers you know we we draw pictures uh and often these pictures are very very generic on this slide you'll see uh you know a very generic

understanding of a system this is just a simple order flow diagram um and what happens is is we design the system and then ultimately you know developers and and operators and Architects have to go out and Implement

these things uh we'll take this we'll cut it down into you know microservices we'll use cues we'll use timers and databases uh what ultimately getting gets delivered in production is fairly

complex and it may seem simple uh you know at its at its surface layer But ultimately inside what we're building the complexities really start to compound

and honestly as you add more features they get exponentially more complex right and so while these these new architectures these modern architectures kind of Promise efficiency and ease and

kind of you know a simple way forward to to implement these applications they often present a lot of different problems because what can go wrong will a database can fail a service can go

down I mean I've spent years in the kubernetes space you know pods coming up and down all the time cues can back up and and ultimately like you know apis

time out all the time uh and and how do you deal with these things as a developer I think in a in a pure state where none of these things go wrong things are pretty simple to deal with

but when things go wrong uh you know we're set dealing with rollback or or retry policies and these sort of things and I think you know people struggle with this sort of stuff and ultimately it detracts away from doing what we

really want to do which is basically deliver the business logic that we've been we've been asked to deliver and and really ultimately even when things go right we still have problems in these in these complex architectures how do you

share State across various different things and I maybe not everybody thinks about it estate but uh where where am I and do I have insight into this overall process for each person that's being

executed across this you know this this complex flow you know can I do uh can I can I perform transactions to a single database across multiple different multiple different Services maybe you

want to do that um you know how do you implement long-running timers how do you wait a month for something to happen let alone a month maybe even three hours for that matter or even 10 minutes even a minute

um are we just putting pauses in code you can't really you know pause pause code so these things get get get really complex even when everything is is working well

and you know I think ultimately and we kind of said this earlier you know as you add more features as you add complexity to the application as the architecture expands it gets even more

difficult and even more complex um you know if you think about retries and rollbacks across three services well what happens when it's 15 or 20 or 30.

the complexity just really compounds and then as you scale and you get more customers you know reliability can suffer as well because there's just more components that can go down and so ultimately you know I think developers

are left dealing with this like they get caught holding the bag right because they're the ones who have to develop all this stuff and they they lose productivity um it gets more difficult to deliver

features faster uh you know the the reliability of our systems as we mentioned kind of goes down and again I'll come back to this this really important point it's really really difficult to get this kind of end-to-end

insight across all the process flows that are going on in in whatever the system is and the application that you're that you're going sure we we may have some observability and some tracing across the services but what's really

going inside that service and how do we know what's actually happening end to end and so ultimately you know I think over the past couple years you know I've seen this happen anybody could go to microservices.io and look at some

development patterns on how these people are how people are actually doing these things development patterns are interesting and I think it's uh the natural inclination of developers to share and figure out how to how to do

this over and over again and I think some of these patterns like a dead letter box uh you know like a saga pattern these sort of things uh they're fantastic uh but but often they'll serve

only one part of the problem uh and I think even further complicating the issue is is we leave it to humans and each developer to implement them in their own way

so they're also prone to to errors or complexity and I think as we move on and I and I think you know ultimately there is a better way to do this Beyond kind of development patterns Beyond just kind

of manually coding all these things and you know one of the reasons I joined temporal was exactly this I think this is a problem that I think I was aware of when I was a developer but I never knew there was going to be a way to actually

figure this in fact I think I I stopped being a developer because I hated doing all this kind of chaos the stuff that I didn't want to do I wanted to focus on business logic and when I think about temporal I I think about it as you know

a developer is is now able to kind of you know build for kind of the the single positive state that they want what is the what is the the way I want people to actually flow through my

application and not worry about the retries the rollbacks uh you know the the the cues the timers uh and and temporal really abstracts away all of that

um we allow developers to code in whatever language well not whatever language but we have sdks across you know go PHP typescript Java python guys correct me if I miss one in the end

there but um uh dotnet.net that's I knew it Max coming soon that's right that's right that's right um you know we allow you to code in your language uh you know Define this workflow which is this end-to-end kind

of positive state that you want in your language and then instrument your code using an SDK to to interact with with temporal so it is really about abstracting in a way this complexity so you can focus really on what matters and

it has a fundamental impact um really on the way that we think about applications I I like to think of it as almost a paradigm shift because I think uh you know the developers I know that have used temporal it's like kind of

once they see it they can't unsee it it is really a a different way of thinking about your application I think it's a incredibly interesting way to to approach software development so

um but I'm joined by you know that's my own my understanding of it I've been at the company and introduced to temporal about eight months ago but I'm sitting with the person who actually created the

project and Max this is not the fist like your first incarnation of this approach is it right I mean there's a history here of you doing this for quite some time right

uh yes uh it it took us probably 15 years to get where we are it's a long time so where did it start like I mean how long ago and how long ago was 15 years as you

told me but where did it start for you I started probably okay I joined Amazon in 2002. yeah yeah and back then Amazon

in 2002. yeah yeah and back then Amazon was I think one of the first companies which decided to kind of break the big monolith into smaller pieces which they

called services and now we call them micro Services back back then it was all services and the reason they did it not because of some kind of

abstract desires or architectural principles it just was taken 45 minutes just to re-link the binary of Amazon website back then so imagine the

developer experience um and uh and I think clean build of that uh binary was 18 hours wow so uh the reasonable solution was to break it into the pieces and then these pieces

had to talk to each other and I was part of the infra team which was responsible for pops up kind of all the messaging between those micro services on the back end and at the end I was checked it for

the service kind of the storage for queues and later it was adopted actually as a simple queue service AWS sqs uses that as a back end uh is somebody who

was responsible for practically talking to every team which was adopting our technology and that ended up kind of getting exposure to a lot of use cases and became pretty clear that Q is

actually not good way to Link services together if you have complex transactions and Amazon Fulfillment flow is non-trivial it actually even back then it was non-trivial I cannot imagine

what it is right now and so we actually uh kind of started to think how to solve that and orchestration became pretty

clear answer to that and Amazon had two kind of multiple iterations on that and uh so practically which resulted as a Amazon simple Buffalo service which is

still publicly the best service but we had two internal versions of that before and then yeah later co-founder of temporal Samar who worked with me on a

simple workflow into Microsoft and uh long story short where Microsoft has a Azure durable functions which are based on the same idea and later we came to Uber and

started like one of the projects we started was Cadence which uh Grew From like zero to 100 use cases within three years and it was open

source from the beginning and I started to get popular like adoption outside of uber and we started a company three and a half years ago and we started we

created a team portal which was kind of continuation of a fork of cadence and we added a lot of new features and now we have to borrow so I I'm sorry but I lost track there how many different it was

what there was one five different incarnations there were some others in between and also it's not only about back-end service it was about client-side experience yeah and we uh I

built at least probably four different Frameworks uh for client-side and first ones were kind of more traditional ones like uh which was kind of oh you create

this DSL and you kind of have objects instantiating them this like there go like uh syntax tree of things you have a sequence you have like split join you have kind of all it's just anything to

think there are like million incarnations of those yeah and it worked uh but I quickly realized it was not a very good developer experience because I just uh much much harder to understand

and troubleshoot and so on so we kind of ended up we implemented this what we call AWS flow framework which was the first idea kind of similar to what temporal does so you just specify your

logic and code directly without any intermediate representation and it didn't we didn't nail the developer experience probably not many people know about simple workflow but later

Microsoft Samara did I think a awesome job with dotnet I think framework like a weight I think and a tuber we did go SDK which was actually synchronous and I think we kind of nailed the developer

experience while doing that well it's interesting I think it's the kind of the core principles that when it is Step functions as well and I think there's this you know it's by my experience as

far as I talked to you know people users of this and I think there's been more than just the five or six that you and Samara have done I think everybody's trying to solve this problem in some form or fashion I think you know once

you see what the problem is it's like oh gosh how do I how do I deal with this you know I think what you all did at Uber was was amazing and you know creating the Cadence project and open

source m T license and then starting a company what makes it right this time um you know like this this incarnation of temporal by the way I'm a absolute believer as well right so what

why is it right this time around can I try to answer it for you first that'd be great it's right this time because it wasn't right all the other times interesting that's good I like the one most constant message that I've heard

from him is that like when people are asking you know like why should we just assume you know all this stuff and you made all these right decisions he's like well I didn't initially that's right first time I made the wrong decision and now I have this long list of decisions

that I should make correctly the next time I have to make them yeah so that's at least what it seems like for me yeah I think the idea is that it's not like we dreamed this overnight it was

just a lot of iterations and a lot of different mistakes and certain things we took us for up to five or six years just to come up with the right abstraction and I think just as a project why I

think we've got to try it is that first we've got developer experience I think correctly and it was a big deal at the same time we built a lot of projects like that they focus on developer experience and forget about the back end

right but because we built simple workflow service before as AWS service so we built this as open source project as a highly scalable practically cloud-based architecture from the

beginning and it was practically so far we couldn't find the point when it breaks yeah it can saturate almost any store practically any storage we we oriented with 300 Cassandra clusters we

have our custom storage which is even more performant and we always able to create a new database to 100 and then and the third thing was because

we builted a tuber as an open source project and uh initially we didn't get like huge adoption but we were running hundreds of use cases high frequency is a tuber uh so practically we kind of

nailed the operational uh excellent yeah because we had to run it for Mission critical use cases and so it means that we kind of got developer experience we got it as open source and we run it at

scale uh at the large company and then uh we've got adoption from external companies which was amazing because like one of the first users were companies

like coinbase Airbnb box uh like doordash and uh this cap these companies uh certain hashicorp and these are not like companies which would take these

things lightly but they trusted us uh because again because all of these reasons yeah I think it's really interesting and I you know I I concur on the developer experience for this is just fantastic you know being able to do

this across multiple different languages you know polygot applications that we have it it's right and I think if you're going to change the model you kind of have to do it across all you couldn't do this in a single language you know what

I mean and I think the the operational kind of getting it to it to a point where it's great um this is all amazing uh do you want to show us the technology Max I mean you

want to give a quick demo okay yeah let's do it I I've been in very few companies where I just asked the CEO to do a demo uh but that's our best demo person right there

because he built it uh so first we run the temporal Service uh which kind of beckoned and usually it's a large-scale distributed system but you can run it as

a single binary with a in-memory database for developing purposes how can someone get that binary if they wanted it yeah you just to do Brew install temporal and if you're on Mac

and in automatic there's a release on the GitHub and you can curl it and install it like a normal Linux package so I want to demo a very simple uh money

transfer use case so practically we have two operations we want to withdraw and we want to deposit money back and if you want to write that like the business logic of that is just two lines

of code right so we call this draw and we call deposit uh obviously nobody writes code like this uh in normal life like at least in

production because obviously if something fails in the middle here uh your process crashes and you lose money which is actually not a good idea

probably if you're a bank so the interesting thing that you actually can write like production code like this with Steam portal so the whole idea is

that temporal guarantee is completion of this code we call it durable execution uh of workflow kind of interchangeably just for kind of Legacy reasons but any

workflow code is guaranteed to complete and keep running in presence of any failure so it means that for example if a failure happens a process crashes

after line 35 here that uh temporal will automatically move this state of this particular manual transfer to a different machine and recover that and

it will keep running so as engineer you don't even notice uh in like as a programmer that there was a failure so it's very powerful because you practically do need a huge class of

issues that disappears you don't even need to think about process crashes other thing if you call this draw service and this service is not reliable uh temporal will automatically retry that as long as necessary so there is no

limitation of duration of retries unless you specify it explicitly in the configuration options and all this retries are fully configurable it's exponential retries and so on and there are a lot of features like rate limiting

flow control and so on which I don't have time to spend on so uh if you want to do this money transfer how would you initiate that so this is actually workflow code and it implements an

interface in this case transfer interface you see I'm in Java uh as we said we have uh sdks and a bunch of other languages but for Java you would

not take a workflow is this workflow interface and Main Muffler method with workflow method otherwise it's just normal Java code so do we implement this in a way that was meant to be very adhering to

temporal or did we try to marry this to the actual idiomatic way that like a Java developer would Implement something in a framework themselves no this is just normal Java right but it's nothing magical but you can use all the Java

constructs so for example if you want to say okay what happens if withdrawal succeeds and deposit fails and in them I didn't do that but then it will just use normal uh

uh uh exception handling from java right and you would run compensation here like let's say put in money back on the original account or you can Implement

Saga full Saga pattern here if you want to so uh but this is like just normal Java code if you want to have a loop if you want to have if like it just you can use all object and design you can move with

another method to even class so just there is no any limitation what you can do here there are some some rules but like you have the full power of java when implementing this code

so let's just try to run it and so uh the idea is that there is this backend service which I just started before uh kind of we have it running in this

window but and also uh when you start the workflow you actually call into that service uh so the only requirement is that temporal Services run when you're

starting that the way you would start it you'll connect to this service all this kind of code is just to connect to the service and then you will uh

just call uh start on that transfer method which we just described here and when it will start is accepted uh

the uh this process will exit and transfer will continue so let's request the transfer it will take some time mostly because it will try to recompile also grade always

not the fastest thing in the world okay we request a transfer we can see that it printed uh okay we don't even want to see what printed imagine it's a distributed

system with thousands of processes running uh temporal provides UI so we can uh this is again uh this local binary which I was running or includes

UI it just hit it on the local host and we can see that there is instance of this workflow running by the way this workflow ID is assigned by you so it's usually a business level uh identifier

and you can use NV granting uniqueness it's fully consistent system so you'll be guarantee uniqueness of workflows by ID so things like idem potency and uniqueness I it's easily to guarantee

because you don't want to transfers with the same ID going at the same time right and do users have any control over that behavior in terms of the ID usage and reusage policy so you cannot

have two workflows open at the same time to save ID ever it's guaranteed but after it's closes you can choose they want to run workflow again with the same ID or they want to run only if it failed

or never run it so you can say never allow running again if it completed or failed for example so here we will see that workflow we have some workflow with

this ID which we started and we can see input arguments of that so these are arguments I passed as a parameters uh there is no result because it's not

completed yet and it will say there is no walk around why because in temporal temporal doesn't run your code even workflow code it's a citizen external process and you deploy this process

anyway you want to just part of your service it's like the way you would for example have your process talks to a database and this is your process talked with temporal backend and workflow code is not running this way this workflow is

not making progress more like qued up in the system so let's run the Walker so I have kind of uh and also in temporal we have a separation between

workflows and activities so workflow would be the code which is uh as I said durable execution is Fault tolerant survives failures and activities just code which talks to external services

and it can fail anytime and we just usually retry it the work focus is doing the orchestrating whereas the activities are the tasks yes it's a workflow it's orchestrator right it's orchestrates

orchestrates those so we we started to run a walker so we can refresh and also just wanted to clarify it makes it sound like what you're saying is that temporal server itself is never running your

actual code this is always taking place on the worker and just events are transparently communicated back and forth on your back yes it's a it's a temporal Services more like middleware right it's kind of it's kind of

encompasses queues and databases and all of that so from your point of your run code your application runs both workflow and activity code and connects to the backend server for State Management and queuing and also durable times and so on

so now we see what happen is that we have a deposit pending activity and it means like how this draw activity probably completed and we see that it's

already it was executed five times and there is a failure going on so we can go and check on that failure and help an account

implementation line 36 and let's find account implementation line 36 and yes and there is exception here actually put this exception just

for the demo purposes but we can see that this activity has been retried and deposit so let's fix this in real life you would just probably fix bug in your code and always fix this service because

maybe there is some other issue is that and redeploy in this case we just restart the uh uh where is it

account activity worker yeah here it is let's just restart this process I use a new code and let's go back to our UI and see what happens so at this at this point

temporal server has statefully and durably tracked the position where my code is executing in the workflow and essentially it's just trying to execute this activity right now and activity is

obviously failing and so what you're trying to do right now is just fix that activity implementation so the next time it retries it'll completely yeah and also obviously I can also kill the

workflow worker which holds the workflow code so we can restart that and we will see that it will recover to exactly the same stated it was so it will adjust it

will like both local doesn't even need to know it was restarted right so we were at the workflow with the line uh uh 38 and right now probably it will

just come already completed because uh it retried the activity yeah so yeah workflow is completed and we can go back and check okay we executed this uh activity

uh first activity withdrawal it was scheduled uh at this time these arguments of this activity it was

started by this process so you see every Everything which happens with what happened then we've got activity

uh deposit scheduled and this activity was executed eight times it failed seven times this is stack trace an exception why it was failing and then it completed

it some time right and then workflow completed so think about it I do need to restart workflow I didn't to do anything I just fixed my bug and the system just

recovered itself and he just won but if you have like million of those running at the same time it's pretty cool that you don't need to do anything it just code recovers automatically in presence of a process crashes and so on you don't

need to do anything as we saw that quote doesn't uh contain any it doesn't need to contain any air logic related to intermittent failures or outages this

area located here is only happens if you have business level failure right for example deposit is not possible because account doesn't exist but at the same time you don't need to handle a situation when process crashed because

it just handled automatically I don't want to spend too much time on that but for example we also have unit testing framework and it means that you can test these workflows even if you have long

grinding uh for example you can absolutely write production code which is workflow.sleep and say something like

is workflow.sleep and say something like duration of this right and sleep like for three days here and it's a blocking call so

it's okay for the process to for example sleep for three days and then continue and then you can Union test it in milliseconds because we automatically skip time for example okay uh so just to

review that you can write a normal code and you have full visibility into this code processing and everything is recorded and you see all I put inputs and arguments and this code recovers

automatically after any intermittent and deployment or failure very very short introduction it's a short introduction but it's very powerful as well Max and I think you

know some of the things it's like yeah there's retries rollbacks we've saw a bunch of stuff I mean even timers were in there at the end right I mean I think schedules is interesting why are people

dealing with KRON today like you use temporal to run things like that and this was just money movement right this was like a bank transfer which you know I think is one of those ways in which people use temporal today you know

high-end transactions where like a bank like you said like that can't fail man it's money right like you it's it's got to work right it's got to be reliable it's got to be durable I think is the word that we like to use around temporal

a fair amount um you know but like this kind of durable transactions is kind of one thing I think people use it for like say you know business processes I don't know I'll ask you I know rylan's one of his favorite use cases is more of a

business process you know people use it for like Inventory management or uh you know you just just understanding things and and having insight into things I I've even seen you know the I think one of the common use cases is like

infrastructure deployment um you know I've seen people end to end you know bring software or you know bring Hardware up run software bring the hardware down like it's incredible like

some of the things that people are doing with temporal um Rylan you've been on the front edge of a lot of uh people using temporal and you've collected a fair amount of like user stories what's

your favorite user story I I think it's impossible to probably just choose one I will say that one thing I want to just make sure I don't uh forget for you know what Max is kind of showing there is that like temporal itself almost does a

disservice to its own technology by making things look so easy and so much more simple than they actually are and so even just something basic like like implementing you know retry statefully

that's an immense amount of code like any developers had to do that no that's daunting and like that's just something that's implicit in the demo that you just saw and so I just wanted to make sure that that was highlighted there in terms of the users I'll choose like a

couple um I think you know some of them are very exciting because they're products that I use and the fact that they're a user of ours is just cool in itself and So like um one example in

that uh areas Yum brands they're the company behind you know a lot of major fast food establishments that probably almost everyone has eaten at once or twice in their life and I'm someone who

eats like hey man tacos pizza and chicken I'm in exactly right and so it's uh it's hard not to say that they're you know an amazing customer just on that basis as someone who spends a lot of

money at their establishments um so I think you know the other part I love about that is kind of going back to this idea that things can look very simple or sound very simple but in reality not be that way you might think that a process

like ordering food or having it delivered isn't isn't that much stuff there isn't that much work there but it's clear from you know the presentations that people have given like Matt from brands that there's an

immense amount of complexity there you could spend days just talking about the complexity of delivering someone's food that orders that you know a Taco Bell and so I think that you know the fact that we took something that's so meaningful to a lot of people's lives

and we were able to you know make it deliverable at such a high scale and with such a great developer experience that's super great exciting for me to see I think another type of customer that's so so exciting is one where I'm like a very strong user of their

products or you know I really like the the brand they've created like datadog um who for like a lot of developers is like a really representative company of modern Cloud development modern Cloud

Trends uh and so you know datadog is unique because they're not just going in on temporal for one use case at this point they are probably one of the most aggressive users of temporal um even beating us out in a lot of ways in terms

of how they adopt and use the technology and so you know it's amazing when you have users that actually are teaching you about your own product on like a regular basis and you know not just teaching us but contributing and you

know helping us deliver things like the temporal CLI experience and all of that and so I think datadog has been like a wonderful partner but also like one of the most Exemplar users and contributors to everything we're doing here at Temple

yeah and the the taco I'm sorry but I got to go back to Young Brands the taco one is the one that actually sold me on temporal in the very beginning it's very simple to understand because I think everybody's gone through that experience

you walk into a store you go to a kiosk you hit the thing you order something the funds get held for a second your credit card doesn't get charged until you get that product right so that happens it goes to the cloud somewhere

Central server it goes back to the store a chef picks it up pushes a button makes the taco pushes a button when they're done puts it on a window the guy up front grabs it puts it to the front they push a button and then your number comes

up and Ryan goes and grabs his taco and then you get charged the amount of complexity in that small little what was that 10 seconds is intense and and all of the things that can go wrong in that

in that equation is is incredible you know that's just one time do it a million times do it a million times and and like if you think about like the Taco Bells like they're in all in like cities with amazing Wi-Fi like a store

can be completely offline and when we talk about durable execution right this this ability to kind of withstram pressure or damage and whatever that is and your system continues no matter what

it's incredible an incredible like use for them because I mean okay maybe they're making 50 cents a taco I don't know what it is but like that's money in the end right and so that's the one use Case by the

way that sold me on temporal I think that that that talk from our conference last year our replay conference was was really really just amazing so um when I really think about temporal I think about kind of like what we can do

that that that word durable uh becomes really really important and you know at temporal we Define this as durable execution because of exactly that it can whisper him pressure um you know this this is this is a

framework that allows you to survive damage of these complex systems that you're building but ultimately when we look at that you know it really helps you kind of deliver more features faster um I I always like to use words it

allows you kind of more elegantly fail you know you might still fail but it's going to be very elegant and you don't have the code for all those kind of situations and then you know maintaining the Integrity of your data and having

Insight end to end to all your processes I think is just you know truly incredible and and I I think don't any fails when you want it to fail that's right because it fails on business problem failures but not on the infrastructure Affairs intermittent

failures deployments and all these other things that's right it's truly amazing and Max Kudos like I'm I'm honored a worker because I really think it's changing the way that developers think and and really changing the way that

people kind of approach problems I've seen it happen time and time again I don't know Rylan what is the best way to get started with temporal so I think some of some of them you saw a demoed you know even with what Max did I think

you know starting with our temporal CLI and just having a very good local development experience um I think like you know philosophically I would say go and watch the presentations from you know amazing

people like Matt mcdole from Young Brands uh and you know uh Drew Hoskins from stripe and Jacob up from datadoga these are all people who are really really amazing at representing the

problems that they solved with the technology and how it transformed not just their lives but all the developers lives that they work with and so that's at least for me what kind of has the biggest impact and kind of and and quite honestly all it's open source so you can

go and start to use temporal today we talked a little bit about date dog their temporal CLI um you know and and if you want to deploy on the cloud we make it real easy for you to run it as a managed Service

as well uh but you know join the conversation our team is uh ever present including Max in slack and support and all the various different places so you

can interact with us we're more than happy to work with you to get you started if you have any questions but Max Ryland thank you for doing this today I hope you enjoyed it did you enjoy this Max absolutely awesome blast

awesome buddy I appreciate it I like talking to you guys anyway so yeah um ah that's thanks buddy thank you everybody

Loading...

Loading video analysis...