bukhgalter

A microservice to share expenses between friends WIP. Class project for the infrastructure subject


Project maintained by yabirgb Hosted on GitHub Pages — Theme by mattgraham

Serverless

Objetivo

Se han creado dos historias de usuario (HU6 HU7). Para cubrir a nivel de backend las necesidades de HU7 se ha decidido crear un servicio serverless para listar las organizaciones que colaboran con el proyecto. No se recibirá ningún parámetro de entrada ya que la HU no toma ninguno y el resultado que se devuelve es una lissta json con la información de los colaboradores.

De cara al usuario, para que pueda ver esta información se creará una interfaz con la que pueda interactuar para obtener esta información.

Elección de la plataforma

Al estar mi código desarrollado en Rust he encontrado dificultades para encontrar plataformas con buen soporte. Me he decantado por Vercel (click para más información) que, aunque no lo soporta de manera oficial, sí cuenta con soporte para Rust hecho por la comunidad. He descartado plataformas como azure por no contar con un soporte bien documentado para Rust o aws por requerir una configuración que no es la convencional y exigir el uso de herramientas muy concretas para Rust.

Código desarrollado

He desarrollado una función que lee una lista en formato string pero con la estructura de un documento json, y la devuelve marcando el tipo de contenido como application/json.

fn handler(_: Request) -> Result<impl IntoResponse, NowError> {
    let response = Response::builder()
        .status(StatusCode::OK)
        .header("Content-Type", "application/json")
        .header("Access-Control-Allow-Origin", "*")
        .body(collaborators.to_string())
        .expect("Internal Server Error");

        Ok(response)
}

El código desarrollado con la configuración se encuentra disponible en bukhgalter-collaborators.

En esta pieza de código lo que estamos haciendo es crear una respuesta http en la que especificamos el código de la misma, que es un documento json, que cualquiera puede hacer una petición al endpoint (he decidido hacerlo así para permitir que otra gente pueda acceder ya que no es contenido crítico). Finalmente le pasamos al cuerpo la cadena json y si algo falla devolvemos un código de error.

Como precaución he seguido el consejo proporcionado en clase y, en lugar de leer un archivo cada vez que se hace una petición, he leido una variable que se lee en tiempo de compilación y está un archivo separado del resto del código. De esta manera se puede generar de manera rápida y automática sin necesidad y no se pierde tiempo en accesos al posible archivo.

Además se ha reducido el tamaño de la respuesta lo máximo posible para consumir únicamente lo necesario en ancho de banda y que la respuesta sea lo más rápida posible.

Se puede hacer una petición en http://bukhgalter-collaborators.vercel.app/. El repositorio ha sido enlazado con vercel

Desplegado de la UI

Para completar el objetivo con la HU mi intención era desplegar una función serverless que me devolviera un archivo html que contuviese un SPA pero he sido incapaz de lograrlo de manera correcta por problemas en como se devuelven los archivos estáticos. Como alternativa he desplegado un bot de Telegram, @bukhgalterbot .

Respecto al SPA que había creado lo realicé porque en local si me funcionaba pero en netlify no por como funciona el almacenamiento de archivos. Dado que esta web también interactua con la app he decido dejarla disponible https://bukhgalter.netlify.app/.

Criterios que he seguido

En primer lugar me he decantado por netlify (click para más información) porque creo que cuenta con muchas herramientas interesantes para desplegar páginas como la que quería crear. Además la interfaz es muy completa y me permite ver claramente lo que está pasando con el sitio web. El rendimiento que he experimentado es muy bueno y no he notado que me haga falta nada que no tenga con netlify.

Respecto al lenguaje utilizado me he decantado por usar node por los siguientes motivos:

El desplegado lo he documentado en un archivo sobre netlify

He obtado usar este repositorio como un monorepo con la excepción de la función serverless de rust. La interfaz se encuentra en la carpeta ui.

Diseño del bot

Para el desarrollo del bot me he valido de la librería que me ha salido en github como más popular, Telegraf. He elegido esta porque tenía lo que me hacía falta para poder crear el bot y en el ejemplo he visto que era fácil de usar. También he usado el ejemplo del propio netlify para desplegar bots de telegram.

En el código he declaro las variables importantes como variables de entorno

La manera de programar es la estandard salvo con la excepción de cómo se ejecuta el mismo

  exports.handler = async (event, ctx, callback) => {
     await bot.handleUpdate(JSON.parse(event.body));
     return callback(null, { statusCode: 200 });
  };

De esta manera le decimos que en lugar de hacer pooling tiene que escuchar las solicitudes que reciba desde el endpoint.

Para enlazar Telegram con el bot mediante he tenido que hacer una petición a la url

https://api.telegram.org/bot{your_bot_token}/setWebhook?url={your_netlify_domain_url}/api/bot

de manera que obtendo el siguiente mensaje

  {
     "ok": true,
     "result": true,
     "description": "Webhook was set"
  }

y queda enlazado el bot con telegram mediante el uso de webhooks.

El bot cuenta con dos ordenes básicas:

Problemas encontrados

  1. El primer problema que he encontrado es que no se puede tener la última versión del microframework web que se usa. La razón es que la librería lambda que sirve para generar una estructura de petición compatible con vercel no es compatible con la nueva versión del microframework web y por tanto no se puede elevar la versión del mismo.

  2. El segundo problema es que la librería disponible para usar vercel con Rust no sigue siendo activamente desarrollada y no están disponibles todas las funcionalidades actuales. La principal que he echado en falta es que no se puede enlazar un proyecto en una subcarpeta por lo que no he podido hacer autodeploy de mi función serverless. Me he decantado por mover lo necesario a un proyecto nuevo bukhgalter-collaborators.

  3. No he encontrado la manera correcta de evitar que se publique la ui en cada commit que hago. Finalmente me he decantado por usar un github actions que realiza una llamada a netlify e inicializa la construcción del sitio. De esta manera solo se construye cuando detecta que hay cambios en la UI.