Skip to content

leticiafrR/pedidos-rust

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

270 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Review Assignment Due Date

Pedidos Rust - Sistema de Pedidos

Presentación y ejecución del sistema.

Presentación y ejecución del sistema

PedidosRust es una nueva aplicación para conectar restaurantes, repartidores y comensales. Gracias a su innovadora implementación distribuida, permitirá reducir los costos y apuntar a ser líder en el mercado.

Para ejecutar el sistema ejecutar los comandos indicados aqui.

Créditos

Nombre(s) Apellido(s) Padrón GitHub
Nilo Josue Martel Valentín 110696 josValentin-fiuba
Andrea Emperatriz Figueroa Rodriguez 110450 AndreaFigueroaR
Lucas Jang 109151 lucasjang01
Leticia Antuaned Figueroa Rodriguez 110510 leticiafrR

Arquitectura

La arquitectura del sistema contará de 5 tipos de procesos con funciones distintas: Comensal, Restaurant, Interfaz Repartidores, Repartidor, Gateway. La cooperación y comunicación de estos 5 procesos para lograr el correcto funcionamiento del sistema Pedidos Rust determina la arquitectura distribuida del mismo.

Procesos principales del sistema

Diagrama de los procesos que conforman el sistema y su interacción general.

La convivencia de estos procesos en el sistema es tal que:

  • Cada proceso Comensal juega un rol de cliente para con las inatancias de: Gateway y de Restaurant. Primero se contacta con el Gateway Lider para iniciar la transaccción y posterior a esta operación se inicia el contacto el Restaurant de su elección para acceder al servicio que este ofrece. Además, de haberse realizado correctamente un pedido al restaurant deseado se abre un socket UDP para poder eventualmente comunicarse con el repartidor que tiene su pedido.

  • El Restaurante le ofrece el servicio al Comensal: tomará o no su pedido, en caso de tomarlo lo cocinará, lo despachará a un delivery y le irá comunicando el estado de dicho pedido al Comensal.

  • A su vez el Restaurant contactará a algún proceso Interfaz Repartidores, eligiendo cual de forma pseudo aleatoria, para acceder al servicio que estos ofrecen.

  • Las instancias de Interfaz Repartidores ofrecen a los retaurants el siguiente servicio:

    • Hacer llegar el pedido disponible a Repartidores cercanos mediante su red de Repartidores.
    • Llevar a cabo el proceso de selección (entre los repartidores interesados)
    • Darle los datos necesarios al Repartidor seleccionado para que se contacte con el restaurant.
  • El repartidor usa el servicio de alguna Interfaz Repartidores para acceder a las publicaciones de pedidos disponibles, decidir si acepta o no los pedidos que le lleguen para poder ser partícipe del proceso de elección, y al saber que es el repartidor elegido para llevar el pedido X se contacta con el restaurant para indicarle que está en camino, así como para comunicar cuando llegue al restaurant. Para concluir con la entrega del pedido se dirigirá a la dirección del comensal y se comunicará con el mismo cuando llegue.

  • Una vez el comensal haya recibido su pedido este se comunica con el Gateway para efectuar el pago o en caso de la ausencia de comunicación por parte del Repartidor se abortará la transacción.

Aplicación comensal

Actores del Sistema

ContactoRestaurante

  • Se comunica con el restaurante por TCP
  • Envía solicitudes de pedido al restaurante
  • Recibe estados del pedido
  • Maneja confirmaciones y cancelaciones

ContactoRider

  • Se comunica con el repartidor por UDP
  • Recibe actualizaciones de ubicación del repartidor
  • Gestiona notificaciones de llegada

ContactoGateway

  • Se comunica con el Gateway de pagos por TCP
  • Procesa autorizaciones de pago
  • Recibe confirmaciones de transacciones
  • Maneja rechazos

Conexion inicial

Al iniciar la aplicación se lee un archivo inmutable que contiene las ubicaciones fisicas y las direcciones de todos los restaurantes. Se fija cuales son los restaurantes cercanos según la ubicación actual del comensal y hace un broadcast por UDP a todos ellos preguntándoles si están conectados, los que le manden un ACK confirmando que están conectados son los que va a considerar para hacer la elección. Cabe aclarar que si no contestan se reintentara un par de veces para verificar que efectivamente están desconectados y que no se haya perdido el paquete.

Conexion inicial del comensal

Flujo de un pedido

Una vez que tiene los restaurantes cercanos y conectados se le muestran al usuario y éste elige uno de ellos para realizar el pedido. Primero se le pide al Gateway de pagos, a través de ContactoGateway, la autorización del pago y éste la puede aceptar o rechazar; si la rechaza se cancela el pedido pero si la acepta el actor ContactoRestaurante envía la solicitud del pedido al restaurante elegido. Desde ahí ContactoRestaurante va recibiendo el estado del pedido hasta que le llega que el repartidor recibió el pedido. Luego el repartidor en cuestión se comunica con el comensal, específicamente con el actor ContactoRider, para ir recibiendo el estado del repartidor. Una vez que ContactoRider recibe que el repartidor llegó a la ubicación del comensal y entrega el pedido, le informa a ContactoGateway que el pedido fue completado, y éste último le envía al Gateway de pagos que finalice la transacción.

Flujo de un pedido

Aplicación Restaurant

Actores del sistema

ControlPedido

  • Gestiona los mensajes entrantes(pedido) y salientes(actualizaciones del estado del pedido) para con el Cliente Comensal mediante una conexión TCP con el mismo.
  • Envía mensaje al actor InterfazPedidos con los datos del comensal, pedido, etc. BackUpChecker
  • Timer con determinada frecuencia para realizar un backup del estado actual de los pedidos del restaurant.
  • Se comunica con la Interfaz Pedidos para indicarle que realice un bakcup en memria persistente del estado actual de los pedidos del restaurant. InterfazPedidos
  • Interfaz central del restaurant accesible para aquellos actores que deban notificar cambios en el estado de pedidos existentes o solcitar la generaci´ón de un estado para un nuevo pedido.
  • Cuando recibe un mensaje para registrar un nuevo pedido:
    • Funciona como punto central donde se generan los IDs unívocos de los pedidos, se genera el estado del pedido identificado y se registra. Además, se mantiene un directorio que vincula el ID con el acceso (addr) al actor ControlPedido (para comunicar cambios en el estado al clentre remoto).
    • Finalmente despacha el pedido al actor Tablero para que eventaualmente empiece su preparación en la Cocina.
  • Recibe mensajes del BackupChecker y los maneja volcando el estado actual de los pedidos en la interfaz en el archivo de caché (recuperabilidad).
  • Recibe actualizaciones del estado de un pedido por parte de la cocina (indicando que terminó su preparación), se registra el cambio de estado, se notifica la actualización al actor ControlPedido correspondiente para su comunicación al cliente remoto y finalmente se le notifica al actor DifusorPedidosSalientes para la gestión de su envío. Tablero
  • Recepciona pedidos nuevos (ya registrados): pasándoselos ahora o eventualnmente a la cocina.
  • Se encarga de mantener una cantidad acotada de pedidos siendo preparados en la cocina. De haber alcanzado el máximo el tablero gestona una cola de pedidos en espera de donde sacará pedidos para ser pasados a la cocina en cuanto haya disponibilidad. (Similar a un semáforo que regula el acceso a la cocina).

Cocina

  • Entidad que recepciona una cantidad acotada de pedidos para simular por cada uno un tiempo de preparación.
  • Posee acceso a la InterfazPedidos y al Tablero. De manera que, en cuanto finaliza la preparación de un pedido:
    • Se notifica el cambio de estado a la InterfazPedidos.
    • Se le comunica el evento al Tablero que posiblemenete tenga pedidos en espera, de modo que este pueda gestionar adecuadamente esta nueva disponibilidad en la cocina.

DifusorPedidosSalientes

  • Entidad que gestiona la conexión TCP con un proceso Interfaz Repartidores para solicitar pertinenetemente la difusión-publicación de un nuevo pedido. Así como, de ser necesario, gestiona la reconexión con alguna replica de proceso Interfaz Repartidores.
  • Al recibir el mensaje de la InterfazPedidos indicando que un pedido terminó de prepararse se arma un mensaje de aplicación con la información relativa al pedido, la ubicación del restaurant, la ubicación destino del comensal, y los datos de puerto al cual el repartidor que fuera a ser elegido debe enviar mensajes (tanto para con este restaurant como para con el comensal) y se lo pasa al proceso Interfaz Repartidores.
  • Además le indica al actor local RecepcionRepartidores que debe gestionar la recepción del mensaje del repartidor para el pedido X indicando que está en camino al restaurant, así como también detectar y reaccionar la ausencia de este mensaje. RecepcionRepartidores
  • Al recibir el mensaje (local) del actor DifusorPedidosSalientes se dispara un timer para el tiempo máximo de espera de la llegada del mensaje del repartidor indicando que está en camino, y se agrega el ID del pedido a la lista de pedidos en espera de rider.
  • Recepciona mediante un socket UDP y gestiona los mensajes entrantes de repatidores que hayan sido seleccionados para llevar a cabo el delivery de alguno de los pedidos que publicamos y hayan indicado que están en camino: se aumenta el tiempo del timer para esperar el siguiente mensaje del repartidor que indique que llegó al restaurant.
  • En caso de no llegar el mensaje de en camino del repartidor le indica al DifusorPedidosSalientes que vuelva a solicitar un rider.
  • Recepciona el mensaje de llegué por el pedido X del repartidor y le indica a la interfaz de pedidos que actualice el estado del pedido (y se lo comunique al cliente remoto indirectamente).

Diagrama de actores de aplicación Restaurant y su interacción

Sistema de repartidores

Componentes

  • Un conjunto de nodos (procesos) que :

    • Cumplen el papel de una interfaz para contactar a los repartidores respecto a un pedido
    • Implementa la estructura del sistema para llevar a cabo la toma de decisiones respecto a qué rider toma un pedido en particular
    • Toma como criterio la cercanía física de los repartidores con los que se conecta para decidir a quiénes notificar de una orden
  • Procesos restaurantes

    • Se conectan con un nodo en particular.
    • Es capaz de contactar automáticamente a otro nodo en caso de que el actual se caiga.
    • Modela la toma de decisiones del rider en el sistema

Diagrama general

Conexión entre los repartidores y las interfaces repartidores

Comunicación inicial

  • Nuestro diseño asigna a cada repartidor el nodo al que se conectará (mediante TCP) siguiendo una distribución uniforme. Si una conexión no se puede establecer se intenta con el siguiente nodo. Si la conexión con un nodo se cae, se retoma con otro nodo disponible.
  • Al lograr establecer una conexión con un nodo de la interfaz, el repartidor debe proveer de su ubicación física a esta.

Procesamiento de un pedido

La interfaz de repartidores recibe ofertas de pedidos de cualquier restaurante, a través de un mensaje UDP, donde el restaurante le provee:

  • La ubicación fisica del local.
  • La dirección IP del restaurante.
  • Ubicación física del comensal.
  • La dirección IP del comensal

Si el nodo ya tiene una votación activa (respecto a qué repartidor toma un pedido en particular):

  • Se reponde al resaturante que su oferta se recepcionó
  • Se encola dicjo pedido

Si el nodo no tiene una votación activa (que se le haya comunicado a este directamente desde un restaurante)

  • Se responde al resaturante que su oferta se recepcionó.
  • Se realiza broadcast a todos los demás nodos para que cada uno inicie una votación interna, indicandoles:
    • ID del nodo que recibió el pedido.
    • La oferta tal como se la pasó el restaurante.
  • El nodo actual inicia su propia votación interna
Votación interna
  • El nodo notifica a sus repartidores que se encuentran en cercanía. Cuenta las respuestas negativas que obtiene, cuenta las respuestas positivas que obtiene. Cada que obtiene una respuesta positiva:

  • Verifica si es mejor que el timestamp más bajo de aceptación que se haya recibido

    • Si la aceptación recibida tiene un timestamp mejor que el anterior entonces se actualiza el timestamp y se notifica al anterior repartidor que no obtuvo el pedido .
    • Si la aceptación recibida tiene un timestamp que no mejora el anterior, se notifica al rider de la respuesta que no obtuvo el pedido.
  • Una vez conseguidas las respuestas a todos los mensajes enviados, el nodo actual realiza un broadcast comunicando:

    • El ID del nodo que recepcionó el pedido
    • El ID del nodo actual
    • El menor timestamp de su votación interna.
  • Realizamos un derivado del algoritmo de Ricard-Agrawala, en donde el nodo que obtiene los Ok de todos los demás nodos, es el nodo ganador de la votación. Los demás nodos obtuvieron al menos una respuesta negativa.

  • El nodo comunica al único rider al cual aún no le dió una respuesta si obtuvo o no el pedido. Si lo obtuvo tambien le proporciona la información de contacto del comensal y del cliente.

Nota: Del lado del nodo que se entera de una oferta de un pedido mediante un broadcast, el mensaje se interpreta como una votación interna que el nodo debe llevar a cabo, realiza el mismo proceso y distingue esta votación interna de una suya por medio del ID del nodo que recepcionó el pedido. Por el mimso detalle de que cada nodo solo puede tener una propia votación activa, aseguramos que en el peor de los casos, cada nodo tendrá N votaciones activas (N siendo la cantidad de nodos)

Comunicación entre repartidor - otros

El repartidor que fue elegido para tomar un pedido, usa la información provista para:

  • Comunicarse con el restaurante para indicar mediante UDP que se encuentra en camino al local
  • Comunicarse con el restaurante para indicar mediante UDP que llegó al restaurante
  • Comunicarse con el comensal para indicar que se encunetra llegó al domicilio.

Actores dentro la interfaz Repartidores

Los actores que se encargan de llevar a cabo el procesamiento de cada pedido son:

  • Restaurantes
    • Representa el actor que posee el socket TCP con puerto público hacia los restaurantes
    • Por medio del sus stream UDP recibe las ofertas de los pedidos
    • Se encarga de mandar respuestas ACK a los restaurantes que enviaron sus ofertas de pedidos
    • Cuando recibe una oferta, envia un mensaje al actor InterfazPedidos para que procese este pedido.
  • InterfazPedidos
    • Representa el actor que gestiona que solo se realice una votación interna propia (hasta que termine y se pueda realizar la siguiente).
    • Tiene una cola con las solicitudes de pedidos de restaurantes y una flag que indica si hay una propia votación interna. Cada que le llega un mensaje del actor Restaurantes se fija la flag
      • Si la flag indica que hay una votación activa entonces se encola el pedido
      • Caso contrario, se cambia la flag, y se le envía un mensaje al actor AdministradorVotaciónActiva para que inicie una votación interna (esta se identifica por medio del ID del nodo que la recepcionó)
    • Cuando AdministradorVotacionesnActiva le comunica que ya no hay una votación activa, procede a desencolar una para inciar una nueva.
  • AdministradorVotacionesnActiva
    • Tiene de stream un Socket UDP interno (deuso exclusivo entre los nodos del subgrafo completo) por el cual se envian mensajes de Broadcast y se reciben mensajes de tipo Broadcast.
    • Tiene una lista de las addresses de los actores RiderAgent
    • La address de InterfazPedidos
    • Por cada votación interna que se esté llevando a cabo, tiene:
      • Un contador de las respuestas negativas (no les interesa el pedido) que recibe
      • Un contador de las respuestas de aceptación que recibe
      • El timestamp y la address del RiderAgent que mantiene el timestamp más pequeño.
      • Las respuestas de los demás nodos de mi timestamp represetantivo para esta votación.
    • Para realizar una votación interna:
      • Envía un mensaje a todos los RiderAgent indicando la ubicación de la oferta
      • Cada que recibe una respuesta actualiza el contador pertinente. En caso de ser una aceptación, el mensaje contiene el timestamp, en base a este valor es que se actualiza la información del menor timestamp.
      • Al terminar de recibir todas las respuestas de esta votación interna, se habrán indicado a todos los RiderAgent que no obtuvieron el pedido, excepto del actor que se asocia al menor timestamp, este es el representante de este nodo en esta votación. Se realiza un llamado recursivo para realizar un broadcast.
      • Para realizar el broadcast usamos el socket UDP para comunicar nuestro timestamp de esta votación interna. Cuando recibe la respuesta de un nodo se actualiza cuanta respuestas se tiene.
        • Si el nodo recibe todos los OK de todos los demás nodos, entonces se le comunica al RiderAgent que le indique al repartidor que tiene el pedido.
        • En caso contrario, comunica al RiderAgent que le indique al repartidor que no obtuvo el pedido.
      • Al comunicar la respuesta al último repartidor que no tenia respuesta, se le comunica a InterfazPedidos que ya no hay una votación activa
  • RiderAgent
    • Representa la conexión TCP con un repartidor.
    • Posee la ubicación física de este repartidor.
    • Puede recibir mensajes de actualización de ubicación, así como mensajes de acpetación de un pedido o rechazo de un pedido.

Actores dentro de los repartidores

  • InterfazRepartidores

    • Mantiene un stream con la conexión TCP del nodo.
    • Tiene el lado de escritura del socket TCP.
    • Tiene la address del actor Repartidor
    • Tiene la ubicación física del repartidor.
    • Cuando se le indica que inicie la comunicación, este solicita conexión a la dirección indicada.
      • Si logra establecer conexión:
        • Setea su stream
        • Actualiza su extremo de escritura
      • Si no puede, le indica a Repartidor que no pudo restablesca la conexión y se indica stop() porque pediró su conexión.
    • Cuando recibe una notificación del stream, le indica a Repartidor que tome una decisión random (que modela la decisión del repartidor)
    • Cuando la conexión del stream falla, le indica al Repartidor que recupere la conexión.
    • Puede comunicarle al otro extremo de la comunicación TCP que la ubicación física del cliente cambió (y cambiarla localmente) cuando el actor Repartidor así lo indique.
  • Repartidor

    • Tiene una lista con un orden aleatorio con las direcciones de los nodos a los que puede conectar. Esta lista la recorre circulamente intenado conectar con algún nodo, corta el recorrido a penas concretiza una conexión. La lista la levanta en base a un archivo inmutable que posee.
    • Tiene la ubicación física del cliente que actualiza después de cada entrega (le indica a InterfazRepartidores que tambien la actualice)
    • Cuando le indican que restablesca la conexión, avanza en la lista de direcciones de los nodos y vuelve a instanciar otro InterfazRepartidores, a quien le indica que establesca conexión con la dirección indicada.

    Actores en la aplicación de repatirdor

Aplicación Gateway de pagos

La instancia de aplicación que se comunicará con los comensales será el líder de un conjunto de nodos que actuarán como registro y réplica de los pagos autorizados por los mismos.

Flujo de un pedido

Actores presentes

ContactoCliente

  • Se comunica con el comensal por TCP
  • Recibe solicitud de authorización de pagos
  • Envía la aceptación o rechazo de tarjeta.

Gateway

  • Mantiene el registro de pagos autorizados en proceso.
  • Recibe actualizaciones de registro de pagos.

ReplicaGateway

  • Registra pagos autorizados en proceso en otros Gateways.
  • Recibe actualizaciones del registro de pagos en proceso del líder.

Flujo

De no existir un líder designado o detectarse la caída del mismo, se procede a la elección de uno nuevo usando el algoritmo Ring. Con el líder establecido, se esperan conexiones de comensales para registrar autorizaciones de pago a travéz del líder. Cada autorización y finalización de pago es transmitida al Gateway líder, y éste retransmite estas actualizaciones a los demás gateways del conjunto, generando respaldo ante caída.

Sistema de autorización y cobro

Diseñamos el sistema como una transacción, basándonos en Two-Phase Commit (2PC). El mismo requiere de la participación de las instancias de todas aplicaciones.

  • Comensal
  • Gateway de pagos
  • Restaurante y Repartidor

Flujo de un pedido

  1. El comensal inicia la transacción al realizar un pedido, recibiendo OK por parte del Gateway de pagos al ser aceptada su tarjeta. En caso contrario se procede al Abort de la transacción.

  2. Recibida la confirmación por parte del Gateway de pagos, se realiza la solicitud del pedido al restaurante. Si el restaurante cancela el pedido, se recibe el Abort. Si se detecta la conexión del restaurante por más de un tiempo determinado, se interpretará también como Abort.

  3. Una vez el repartidor recoge el pedido, esperamos recibir su OK (al llegar a la ubicación del comensal). Hasta entonces esperamos recibir mensajes Keep Alive(KA) de su parte. De no recibir KAs hasta luego de cierto tiempo, se considerará como Abort.

  4. Recibida la confirmación del repartidor, el comensal procede al Commit efectuando el "cobro".

  5. De detectarse un Abort, realizamos la limpieza de la autorización en el registro del gateway de pagos.

Ejecución del programa

  • Aplicaciones Rider

    • Rider Interface

      cargo run -p rider --bin riders_interface <ID_node>

      ID_node: es un numero entre el 0 y el máximo numero de nodos (actualmente 5)

    • Rider

      cargo run -p rider --bin rider "Rider {nombre del rider}"

      Los nombres de los riders son letras que van de la A a la T, en orden alfabetico. Por ejemplo:

      cargo run -p rider --bin rider "Rider A"
  • Aplicación Restaurante

    Para ejecutar los siguientes comandos es necesario estar posicionados en el directorio restaurant. Entonces, desde la raíz del proyecto:

    cd restaurant 

    Luego

    cargo run "Restaurant {nombre del restaurante}"

    Los nombres de los restaurantes son letras que van de la A a la J, en orden alfabetico. Por ejemplo:

    cargo run "Restaurant A"

    Además, opcionalmente se puede levantar el restaurante con las siguientes flags:

    • --verbose para mostrar más información de las acciones que suceden en el restaurant.
    • --recovery para levantar el restaurante desde el backuop (si existe) y poder retomar pedidos preparados recientemente (2 min).
  • Aplicación Gateway de Pagos

    cargo run --package gateway --bin gateway

    Opcionalmente podemos ejecutarlo en modo verbose:

    cargo run --package gateway --bin gateway -- -v
  • Aplicación Comensal

    Para ejecutar el prgrama de un restaurant ubíquese primero en el directorio costumer, desde la raíz del proyecto:

    cd costumer

    Luego

    cargo run "Costumer {nombre del comensal}"

    Los nombres de los comensales son letras que van de la A a la J, en orden alfabetico. Por ejemplo:

    cargo run "Costumer A"

Cambios realizados

Aplicación Comensal

Actores agregados

ConnectionManager

  • Se encarga de buscar los restaurantes cercanos que están conectados a través de mensajes UDP

UserInteractionManager

  • Es el "Instrucciones input" del diagrama. Se encarga de presentar al usuario las opciones de restaurantes disponibles y solicitarle que seleccione uno.

ReconnectionSupervisor

  • Si el restaurante se desconecta, el actor RestaurantContact finaliza su ejecución. Este actor se encarga de intentar restablecer la conexión con el restaurante caído repetidas veces y, una vez que lo logra, vuelve a crear a RestaurantContact para completar el flujo de la orden.

GatewayReconnectionSupervisor

  • Si el gateway se desconecta, el actor GatewayContact finaliza su ejecución. Este actor se encarga de intentar restablecer la conexión con el gateway caído indefinidamente y, una vez que lo logra, vuelve a crear a GatewayContact para completar la transacción.

Archivos agregados

Se agregaron archivos json para manejar la persistencia y recuperabilidad de los pedidos tanto para RestaurantContact, RiderContact y GatewayContact.

Mensajes agregados

Además de los mensajes mostrados en el diagrama originalmente, estos son los mensajes agregados más importantes:

  • StartDelivery: RestaurantContact -> RiderContact
  • CancelDelivery: RestaurantContact -> RiderContact
  • CancelTransaction: RestaurantContact -> GatewayContact

En el diagrama original no se detallaban los diferentes escenarios de caída del comensal o de aplicaciones externas. Cada uno de estos casos requiere un manejo particular y, en algunos, es necesario cancelar los pedidos, lo que motivó la incorporación de estos mensajes.

En el caso de StartDelivery, anteriormente RiderContact consideraba iniciado el delivery al recibir el mensaje "OnTheWay" del rider asignado. Sin embargo, si el comensal estaba caído en ese momento, el viaje nunca se daba por iniciado. Ahora, el delivery se considera iniciado cuando RestaurantContact envía el mensaje StartDelivery, que ocurre al recibir el mensaje "Delivering" del restaurante, indicando que el rider ya tiene el pedido y está en camino.

Nota: Solo es posible recuperar pedidos que hayan alcanzado el estado Prepared y siempre que el comensal se reconecte dentro de los 2 minutos posteriores a la caída del restaurant. Los pedidos en estados anteriores no pueden ser recuperados.

Aplicación Interfaz Repartidores

Cambios en los actores

Actor Semántica Nombre viejo (si ya existía)
OtherNodesAgent Abstracción de la comunicación entre nodos (vía UDP) La responsabilidad era de AdministradorVotacionesnActiva, solo se delegó
OrderManager Administrador de las ordenes recibidas directo desde los restaurantes dentro de un nodo La responsabilidad era de AdministradorVotacionesnActiva, solo se delegó
Restaurant Agent Comunicación con cada restaurante atendido en el nodo Restaurants
VotingSystem Administrador de múltiples votaciones llevándose a cabo dentro de un nodo. Puente para conecta a cualquier VotingInProgress de forma segura. La responsabilidad era de AdministradorVotacionesnActiva, solo se delegó
VotingInProgress Representación de un una votación de una orden llevándose a cabo La responsabilidad era de AdministradorVotacionesnActiva, solo se delegó. La idea preexistente se denominó VotaciónInterna

Cambios en los mensajes

Mensaje(s) Semántica Nombre viejo (si ya existía)
ResultInternalVoting Mensajes entre nodos (vía UDP) Es una "implementación" de un BroadcastMsg. La idea ya existía
NewOrder Mensajes entre nodos (vía UDP) Es una "implementación" de un BroadcastMsg. La idea ya existía
Ack Mensajes entre nodos (via UDP) Es una "implementación" de un BroadcastMsg. La idea ya existía
WinnerByTimeout Mensajes entre nodos (via UDP) Es una "implementación" de un BroadcastMsg. La idea surge debido a los timeouts para recibir resultados de otros nodos respecto a una misma orden.
Wrappers... Mensajes entre actores respecto comunicación entre nodos (vía UDP) No existía
LeaveVoting,
AcceptOrder, RejectOrder
Comunicación saliente del RiderAgent al VotingSystem No existía
HandshakeMsg, DeleteRiderLocation, UpdateRiderLocation Mensajes del actor RiderAgent a RiderLocationGuard No existía
NewOrder Mensaje autoncontenido para iniciar una votación en todos los nodos. Construida por VotingInProgress Ya existía pero se le agregó más metadata. La responsabilidad de enviarlo era de AdministradorVotacionesnActiva.
NewVotation Mensaje entre actores a partir de NewOrder agregando metadada necesaria para iniciar la votación No existía
ResultInternalVoting Un nodo comunica el resultado de una votación en particular Nombre no definido
EndVotingForTimeout Mensaje de actores para evitar bloqueo del flujo de realización de votaciones propias en un nodo (VotingInProgress a sí mismo) No existía

Cambios en el sistema distribuido

La comnicación con un restuarante con una interfaz se realiza a travéz de una conexión TCP (aprovechamos la comunicación reliable ).

Convenciones

Todos los actores que representan una conexión con otro extremo de comunicación (es decir, que manejan el stream de entrada y el extremo de escritura) poseen un subfijo "Agent" en el nombre del actor.

Cambios en el sistema interno

La votación interna de un pedido en particular cuenta con un timeout. Si es que los riders contactados para una votación interna se tardan mucho en responder se termina la votación con los riders que ya hayan respondido, de esta forma, el flujo de ordenes "internas" (es decir que se recibieron via TCP directo de un restaurante) no se ve atascado en caso de que un rider no responda. Véase el procedimiento para procesar un pedido desde la perspectiva de un nodo para obtener más detalles de los cuidados tomados debido a la introducción del timeout antes no planteado.

Aplicación rider

Respecto al manejo de múltiples ofertas

Como los riders pueden recibir múltiples ofertas de diferentes resaturantes, se agregó una cola de ofertas pendientes para responder, de esta forma no permitimos inconsistencias dejando a un rider aceptar dos publicaciones de ordenes.

Respecto a la persistencia de datos

Cuando llega al restaurante y se recibe el pedido se guarda en disco por si la aplicación falla. Esto es que si ya se indicó al restaurante que este rider realizará el envío, entonces se realiza el backup con la información necesaria para poder retomar el pedido:

pub struct DeliveryState {
    pub order_publishing: OrderPublishing,
    pub pickup_timestamp: u64,
    pub delivery_duration_secs: u64,
}

NOTA: delivery_duration_secs es el tiempo que se habia estimado en llegar al destino.

  • Si es que al recuperase el tiempo desde que se recogió el pedido desde el restaurante ya excedió el tiempo estimado de entrega: se asume que el pedido ya se realizó y el costumer recibió su orden.
  • Si es que al recuperase, el rider sigue en trayecto, se retoma desde alli. (entonces se lleva a cabo el envio del mensaje al costumer indicando que el rider llegó a su ubicación )

Aplicación Gateway de pagos

Actores agregados

  • TcpSender: Se encarga del envío de datos a través del lado de escritura de un socket TCP, vinculado a un cliente.

Actores eliminados

  • ReplicaGateway: Se removió el actor en favor de la simplicidad de envío de datos a través de sockets UDP.

Mensajes agregados

  • SendDataToNext: Gatway -> Gateway(Remote)
  • SendDataSafe: Gatway -> Gateway(Remote)
  • RecvFromRing: Gateway(Remote) -> Gateway
  • KeepLeaderAlive: Gateway -> Gateway(Remote, Leader)
  • ClientRegister: CostumerContact -> Gateway(Leader)
  • ClientCommit: CostumerContact -> Gateway(Leader)
  • ClientAbort: CostumerContact -> Gateway(Leader)

Detalles no contemplados en el diseño original

Al levantarse una instancia de Gateway, ésta trata de encontrar al líder actual, de no encontrarlo, se autoproclama líder. De existir un líder, éste recibirá el mensaje y le responderá con el registro de clientes actual.

La instancia líder, que se comunica con los clientes, al procesar el registro de los mismos les asignará un id, el cuál será la clave para realizar COMMITS y ABORTS futuros.

Aplicación Restaurant

Tareas lanzadas al iniciar el programa:

A diferencia de lo planteado en el diseño inicial, en la presnte entrega, se implementó el lanzamiento de 2 tareas asincrónicas adicionales al ejecutar la aplicación (inicio), estas precisamente cubren los siguientes aspectos:

  1. Abrir un socket UDP (no bloqueante) vinculado al puerto público para comensales e iniciar un loop en el que se reciban mensajes de los posibles copmensales (comensales interesados en saber si el restaurant está atendiendo) y se delegue su procesamiento y respuesta asicrónica a un actor nuevo PosibleCustomerCommunication.
  2. Abrir un socket UDP (no bloqueante) vinculado al puerto público para riders e inciar un loop en el que se reciban los mensajes de los riders que tienen que recoger algún pedido del restauran y se dirija su procesamiento y posible respuesta al actor RidersWaiter. Esto en contraste con el anterior diseño que solo planteaba la apertura de una tarea inicial que aperture el socket TCP vinculado al puerto público para los comensales y ejecutase el loop en que se acepten conexiones y se delegue el seguimiento a esta conexión (procesamiento de mensajes recibidos y respectivas respuestas) al actor dedicado CustomerCommunication.

Actores del sistema

Como se mencionó previamente se agregaron dos actores nuevos: PosibleCustomerCommunication y CustomerCommunication, además de esto los actores planteados en el rpimer diseño se vieron modificados de la siguiente foirma:

  • OrdersInteface: Ahora también incluye la lógica para manejar que el servicio de publicación no esté disponible y cuando vuelve a estar disponible:
  • Se maneja un mensaje que indica que el servicio de publicación de pedidos no está disponible de manera que futuros pedidos no sean aceptados como precaución y se refleja en el estado interno (el publisher_addr pasa de ser Some a None)
  • Frente a la preparación de un pedido y la necesidad de publicarlo, en caso de no tener disponible el servicio de publicación se guarda como pendiente a los pedidos que deberían ser publicados para que se manejen adecuadamente cuando el servicio vuelva a estar disponible
  • Se maneja el mensaje que indica que se logró reestablecer la conexión con el sevicio de riders para que futuros pedidos puedan ser aceptados y se republiquen aquellos pedidos que no pudieron ser publicados anteriormente.
  • OrdersPublisher: Se agregó la lógica necesaria para gestionar el establecimeinto, pérdida y recuparación de la coenxión con alguna instancia de RidersInterface puesto que no tiene sentido que el restaurante acepte nuevos pedidos si no tiene acceso a algú servicio de delivery. Por lo cual resultó necesario agregar comunicación entre este actor y el OrdersInterface que comunique el estado de la disponibilidad del servicio externo.

Nuevas políticas definidas

Política de publicación de pedidos

Se estableció que el servicio RidersInterface opera bajo el principio de best effort. El sistema tolera un tiempo considerable para que se desarrolle la votación y el rider seleccionado (de existir) establezca comunicación con el restaurant. En caso de no recibir el primer mensaje del rider como confirmación de éxito en la operación, el restaurant es responsable de recontactar su RidersInterface para republicar el pedido hasta lograr la confirmación.

Política de desconexión de clientes

Se definieron las siguientes políticas para el manejo de desconexiones de clientes con pedidos en curso:

  • Pedidos en estado previo a Prepared: Se desestima el pedido. Se acuerda con el Customer que no se realizarán intentos de recuperación y el pedido deja de ser responsabilidad del Restaurant.

  • Pedidos en estado Prepared o posterior: Se acuerda que la aplicación Customer eventualmente se reconectará con el Restaurant para recuperar el seguimiento de su pedido. Por esta razón, el restaurant continúa con la publicación del pedido.

Política de recuperación ante caídas del sistema

Para recuperarse de una caída, el restaurant restaura pedidos que cumplen las siguientes condiciones:

  • Se encontraban en estado Prepared
  • No se ha guardado su estado hace más de dos minutos

Cuando el Restaurant se levanta en modo --recovery, el cliente que tenía un pedido en estado Prepared y perdió conexión dispone de una ventana de 2 minutos para reconectarse con el restaurant y enviar un mensaje de recuperación del seguimiento del pedido.

Casos especiales:

  • Pedidos en otros estados: No se restauran desde el backup, ya que el customer no intentará contactarse para recuperar su seguimiento.
  • Pedidos Prepared con más de 2 minutos de antigüedad: Tanto el restaurant como el Cliente ejecutan las acciones necesarias para reflejar la cancelación del pedido.

Resumen de políticas relevantes

  • Solo se recuperan pedidos en estado Prepared y dentro de los 2 minutos posteriores a la caída.

  • La publicación de pedidos a través de la interfaz de repartidores es best effort y se reintenta si no hay confirmación del rider.

  • Los pedidos en estados previos a Prepared no se restauran ni se recuperan.

  • En caso de no recibir el primer mensaje de contacto del rider en 20 segundos, el restaurant considera que la operación no fue exitosa y reintentará la publicación del pedido a través de la interfaz de repartidores, siguiendo la política de best effort definida para el sistema.

Diseños actualizados

Sistema de autorización y cobro

Flujo de un pedido

Gateway de pagos

Flujo de un pedido

About

Sistema interno de concurrencia distribuida con resiliencia de datos y tolerancia a fallos en el contexto de "Pedidos Rust", un aplicativo de un sistema de servicio de entrega de pedidos.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages