@@ -307,7 +307,226 @@ <h4 id="_bundling_of_different_logical_domains"><a class="anchor" href="#_bundli
307307< h3 id ="_refactoring "> < a class ="anchor " href ="#_refactoring "> </ a > < a class ="link " href ="#_refactoring "> 1.2. Refactoring</ a > </ h3 >
308308< div class ="paragraph ">
309309< p > In this section, we’ll refactor the Cabs application.
310- The refactoring will be limited to make the process easy to understand.</ p >
310+ The refactoring will be limited to make the process easy to understand.
311+ The scope of the refactoring will be the extraction of drivers module, which is already a separate domain in the codebase.
312+ Within the scope of the < code > completeTransit</ code > method, we’ll need to shift the way we calculate the fee for the driver.
313+ The calculation will be done asynchronously, and when the driver module publishes the calculation result, it will be saved back into the database.</ p >
314+ </ div >
315+ < div class ="paragraph ">
316+ < p > The base for the refactoring is the < em > Event Mesh</ em > pattern, and the asynchronous communication will be done with < em > Cloud Events</ em > .</ p >
317+ </ div >
318+ < div class ="sect3 ">
319+ < h4 id ="_drivers_module "> < a class ="anchor " href ="#_drivers_module "> </ a > < a class ="link " href ="#_drivers_module "> 1.2.1. Drivers module</ a > </ h4 >
320+ < div class ="paragraph ">
321+ < p > The functionality around drivers is already quite separated in the codebase, so it is a good staring point to extract into a separate module.
322+ The drivers module will become a standalone web service, deployed on the < em > Kubernetes</ em > cluster.
323+ The implementation of the drivers module will be done with < em > Rust</ em > for this example.</ p >
324+ </ div >
325+ < div class ="paragraph ">
326+ < p > Here’s the < em > Rust</ em > code for calculate fee functionality.
327+ The entrypoint is the < em > Cloud Event</ em > of type < code > cabs.drivers.calculate-fee</ code > we are expecting the < em > Event Mesh</ em > will route.</ p >
328+ </ div >
329+ < div class ="listingblock ">
330+ < div class ="content ">
331+ < pre class ="highlightjs highlight "> < code class ="language-rust hljs " data-lang ="rust "> impl Service {
332+ pub async fn calculate_fee(&mut self, ce: Event) -> Result<()> {
333+ let fee_event = Self::parse_fee_event(ce)?; < i class ="conum " data-value ="1 "> </ i > < b > (1)</ b >
334+ let subject = fee_event.id.clone();
335+
336+ let drv = self.repo.get(&fee_event.entity.driver_id).await?;
337+
338+ let fee = drv.calculate_fee(&fee_event.entity.transit_price); < i class ="conum " data-value ="2 "> </ i > < b > (2)</ b >
339+
340+ let fee_event = DriverFeeEvent {
341+ driver_id: fee_event.entity.driver_id,
342+ fee,
343+ }; < i class ="conum " data-value ="3 "> </ i > < b > (3)</ b >
344+
345+ let mut builder = fee_event.to_builder(); < i class ="conum " data-value ="3 "> </ i > < b > (3)</ b >
346+ if let Some(id) = subject {
347+ builder = builder.subject(id);
348+ } < i class ="conum " data-value ="3 "> </ i > < b > (3)</ b >
349+ let ce = builder.build().map_err(error::ErrorInternalServerError)?; < i class ="conum " data-value ="3 "> </ i > < b > (3)</ b >
350+
351+ Sender::new(&self.config).send(ce).await?; < i class ="conum " data-value ="4 "> </ i > < b > (4)</ b >
352+
353+ Ok(())
354+ }
355+ // [..]
356+ }</ code > </ pre >
357+ </ div >
358+ </ div >
359+ < div class ="paragraph ">
360+ < p > In the above code, we are doing the following:</ p >
361+ </ div >
362+ < div class ="colist arabic ">
363+ < table >
364+ < tr >
365+ < td > < i class ="conum " data-value ="1 "> </ i > < b > 1</ b > </ td >
366+ < td > We are parsing the internal, business logic, fee event from the < em > Cloud Events</ em > envelope.</ td >
367+ </ tr >
368+ < tr >
369+ < td > < i class ="conum " data-value ="2 "> </ i > < b > 2</ b > </ td >
370+ < td > We are calculating the fee for this event, using some business logic.</ td >
371+ </ tr >
372+ < tr >
373+ < td > < i class ="conum " data-value ="3 "> </ i > < b > 3</ b > </ td >
374+ < td > We are wrapping the calculated fee into the < em > Cloud Events</ em > envelope.</ td >
375+ </ tr >
376+ < tr >
377+ < td > < i class ="conum " data-value ="4 "> </ i > < b > 4</ b > </ td >
378+ < td > We are sending the fee back to the < em > Event Mesh</ em > using < em > HTTP REST</ em > client.</ td >
379+ </ tr >
380+ </ table >
381+ </ div >
382+ < div class ="paragraph ">
383+ < p > Of course, in order for this method to be called, we need to route the event from the HTTP listener:</ p >
384+ </ div >
385+ < div class ="listingblock ">
386+ < div class ="content ">
387+ < pre class ="highlightjs highlight "> < code class ="language-rust hljs " data-lang ="rust "> pub fn routes() -> impl HttpServiceFactory + 'static {
388+ web::resource("/").route(web::post().to(recv))
389+ }
390+
391+ async fn recv(
392+ ce: Event,
393+ state: web::Data<State>,
394+ binding: web::Data<Binding>,
395+ ) -> Result<HttpResponse> {
396+ log::info!("Received event:\n{}", ce);
397+
398+ let mut svc = service::new(state, binding).await?;
399+
400+ match ce.ty() {
401+ "cabs.drivers.calculate-fee" => svc.calculate_fee(ce).await,
402+ _ => Err(error::ErrorBadRequest("unsupported event type")),
403+ }?;
404+
405+ Ok(HttpResponse::Ok().finish())
406+ }</ code > </ pre >
407+ </ div >
408+ </ div >
409+ < div class ="paragraph ">
410+ < p > Let’s see also the < em > Cloud Event</ em > sender, that uses the < em > HTTP REST</ em > client to send events to the < em > Event Mesh</ em > :</ p >
411+ </ div >
412+ < div class ="listingblock ">
413+ < div class ="content ">
414+ < pre class ="highlightjs highlight "> < code class ="language-rust hljs " data-lang ="rust "> impl Sender {
415+ pub async fn send(&self, ce: Event) -> Result<()> {
416+ log::debug!("sending {} event to {}:\n{:?}", ce.ty(), &self.sink, ce,);
417+
418+ let response = self
419+ .client
420+ .post(&self.sink) < i class ="conum " data-value ="1 "> </ i > < b > (1)</ b >
421+ .event(ce)
422+ .map_err(error::ErrorInternalServerError)?
423+ .send()
424+ .await
425+ .map_err(error::ErrorInternalServerError)?;
426+
427+ match response.status().is_success() {
428+ true => Ok(()),
429+ false => {
430+ log::error!("failed to send event: {:#?}", response);
431+ Err(error::ErrorInternalServerError(format!(
432+ "failed to send event: {}",
433+ response.status()
434+ )))
435+ }
436+ }
437+ }
438+ }</ code > </ pre >
439+ </ div >
440+ </ div >
441+ < div class ="admonitionblock note ">
442+ < table >
443+ < tr >
444+ < td class ="icon ">
445+ < i class ="fa icon-note " title ="Note "> </ i >
446+ </ td >
447+ < td class ="content ">
448+ < div class ="colist arabic ">
449+ < table >
450+ < tr >
451+ < td > < i class ="conum " data-value ="1 "> </ i > < b > 1</ b > </ td >
452+ < td > The client uses < em > POST</ em > method, to send the < em > JSON</ em > representation of the event to the sink.
453+ The < em > sink</ em > is the URL of the target, in this case the url of the < em > Event Mesh</ em > .</ td >
454+ </ tr >
455+ </ table >
456+ </ div >
457+ </ td >
458+ </ tr >
459+ </ table >
460+ </ div >
461+ </ div >
462+ < div class ="sect3 ">
463+ < h4 id ="_event_mesh "> < a class ="anchor " href ="#_event_mesh "> </ a > < a class ="link " href ="#_event_mesh "> 1.2.2. Event Mesh</ a > </ h4 >
464+ < div class ="paragraph ">
465+ < p > In this section, we’ll use the < em > Event Mesh</ em > setup to communication between the different parts of refactored code.</ p >
466+ </ div >
467+ < div class ="paragraph ">
468+ < p > Here’s the < em > Event Mesh</ em > central component configuration, the < em > Broker</ em > , which will be used in this example.
469+ The < em > Broker</ em > here is the < em > Knative</ em > component, and will be deployed in the < em > Kubernetes</ em > cluster.</ p >
470+ </ div >
471+ < div class ="listingblock ">
472+ < div class ="content ">
473+ < pre class ="highlightjs highlight "> < code class ="language-yaml hljs " data-lang ="yaml "> apiVersion: eventing.knative.dev/v1
474+ kind: Broker
475+ metadata:
476+ name: default
477+ namespace: demo
478+ spec:
479+ delivery:
480+ backoffDelay: PT0.2S < i class ="conum " data-value ="1 "> </ i > < b > (1)</ b >
481+ backoffPolicy: exponential < i class ="conum " data-value ="2 "> </ i > < b > (2)</ b >
482+ retry: 10 < i class ="conum " data-value ="3 "> </ i > < b > (3)</ b > </ code > </ pre >
483+ </ div >
484+ </ div >
485+ < div class ="colist arabic ">
486+ < table >
487+ < tr >
488+ < td > < i class ="conum " data-value ="1 "> </ i > < b > 1</ b > </ td >
489+ < td > The < code > backoffDelay</ code > is the delay between retries, and us use < code > 200ms</ code > initially.</ td >
490+ </ tr >
491+ < tr >
492+ < td > < i class ="conum " data-value ="2 "> </ i > < b > 2</ b > </ td >
493+ < td > The < code > backoffPolicy</ code > is set to < code > exponential</ code > , which means that the delay will be doubled each time.</ td >
494+ </ tr >
495+ < tr >
496+ < td > < i class ="conum " data-value ="3 "> </ i > < b > 3</ b > </ td >
497+ < td > The < code > retry</ code > is the number of times we retry before giving up.</ td >
498+ </ tr >
499+ </ table >
500+ </ div >
501+ < div class ="admonitionblock important ">
502+ < table >
503+ < tr >
504+ < td class ="icon ">
505+ < i class ="fa icon-important " title ="Important "> </ i >
506+ </ td >
507+ < td class ="content ">
508+ < div class ="paragraph ">
509+ < p > Because the policy is < code > exponential</ code > , the maximum time the < em > Broker</ em > will be retrying is 6 min and 49 sec.
510+ In the above configuration, after that time is reached, the event will be dropped.</ p >
511+ </ div >
512+ </ td >
513+ </ tr >
514+ </ table >
515+ </ div >
516+ < div class ="admonitionblock note ">
517+ < table >
518+ < tr >
519+ < td class ="icon ">
520+ < i class ="fa icon-note " title ="Note "> </ i >
521+ </ td >
522+ < td class ="content ">
523+ < div class ="paragraph ">
524+ < p > A < code > deadLetterSink</ code > could be configured for the < em > Broker</ em > to send the events that failed to be delivered in time to a back-up location.
525+ Events captured in a back-up location can be re-transmitted into the < em > Event Mesh</ em > later.</ p >
526+ </ div >
527+ </ td >
528+ </ tr >
529+ </ table >
311530</ div >
312531< div class ="imageblock ">
313532< div class ="content ">
@@ -318,7 +537,7 @@ <h3 id="_refactoring"><a class="anchor" href="#_refactoring"></a><a class="link"
318537< p > The diagram illustrates the flow of events between the legacy application, the Knative < em > Event Mesh</ em > , the fee calculator service, and the datastore.</ p >
319538</ div >
320539< div class ="paragraph ">
321- < p > In this video you can see xpto :</ p >
540+ < p > In this video you can see the above example presented by Red Hat' employee < a href =" https://github.com/cardil " > Chris Suszynski </ a > :</ p >
322541</ div >
323542< div class ="videoblock ">
324543< div class ="content ">
@@ -331,40 +550,21 @@ <h3 id="_refactoring"><a class="anchor" href="#_refactoring"></a><a class="link"
331550</ div >
332551</ div >
333552</ div >
553+ </ div >
334554< div class ="sect1 ">
335555< h2 id ="_run_the_demonstration "> < a class ="anchor " href ="#_run_the_demonstration "> </ a > < a class ="link " href ="#_run_the_demonstration "> 2. Run the demonstration</ a > </ h2 >
336556< div class ="sectionbody ">
337557< div class ="sect2 ">
338558< h3 id ="_before_getting_started "> < a class ="anchor " href ="#_before_getting_started "> </ a > < a class ="link " href ="#_before_getting_started "> 2.1. Before getting started</ a > </ h3 >
339- < div class ="paragraph ">
340- < p > To run this demo, you will need xpto.
341- Adding to that, make sure to have:</ p >
342- </ div >
343- < div class ="ulist ">
344- < ul >
345- < li >
346- < p > ABC</ p >
347- </ li >
348- < li >
349- < p > XYZ</ p >
350- </ li >
351- < li >
352- < p > XPTO</ p >
353- </ li >
354- </ ul >
355- </ div >
559+
356560</ div >
357561< div class ="sect2 ">
358562< h3 id ="_installing_the_demo "> < a class ="anchor " href ="#_installing_the_demo "> </ a > < a class ="link " href ="#_installing_the_demo "> 2.2. Installing the demo</ a > </ h3 >
359- < div class ="paragraph ">
360- < p > Installation guide and basic test of the demo installation if needed</ p >
361- </ div >
563+
362564</ div >
363565< div class ="sect2 ">
364566< h3 id ="_walkthrough_guide "> < a class ="anchor " href ="#_walkthrough_guide "> </ a > < a class ="link " href ="#_walkthrough_guide "> 2.3. Walkthrough guide</ a > </ h3 >
365- < div class ="paragraph ">
366- < p > How to run through the demo</ p >
367- </ div >
567+
368568</ div >
369569</ div >
370570</ div >
0 commit comments