One place for hosting & domains

      agregar

      Cómo agregar espacio de intercambio en Ubuntu 20.04


      Introducción

      Una opción para evitar errores de memoria insuficiente en aplicaciones es agregar espacio de intercambio a su servidor. En esta guía, abordaremos la manera de añadir un archivo de intercambio a un servidor Ubuntu 20.04.

      Advertencia: Si bien, en general, el intercambio se recomienda para sistemas que utilizan discos duros giratorios tradicionales, utilizarlo con SSD puede causar problemas de degradación de hardware con el paso del tiempo. Debido a esta consideración, no recomendamos habilitar el intercambio en DigitalOcean ni en ningún otro proveedor que utilice almacenamiento SSD.

      ¿Qué es el espacio de intercambio?

      El Swap es una porción de almacenamiento de las unidades de disco duro que se reserva para el sistema operativo, a fin de almacenar de forma temporal datos que ya no es posible contener en la memoria RAM. Esto le permite aumentar la cantidad de información que su servidor puede conservar en su memoria funcional, con algunas advertencias. El espacio de intercambio en el disco duro se utilizará principalmente cuando ya no haya espacio suficiente en la RAM para mantener datos de aplicación en uso.

      La información escrita en el disco será considerablemente más lenta que la información conservada en la RAM, aunque el sistema operativo preferiría seguir ejecutando datos de aplicación en la memoria y utilizar el espacio de intercambio para los datos antiguos. En general, disponer de espacio de intercambio como una segunda opción para cuando la RAM de su sistema se agote puede funcionar como una buena red de seguridad contra excepciones por falta de memoria en sistemas con almacenamiento no SSD disponible.

      Paso 1: Comprobar la información de intercambio del sistema

      Antes de empezar, podemos verificar si el sistema ya cuenta con espacio de intercambio disponible. Es posible contar con una variedad de archivos o particiones de intercambio, pero generalmente debería bastar con uno de ellos.

      Podemos ver si el sistema cuenta con algún intercambio configurado ingresando lo siguiente:

      Si no obtiene ningún resultado, esto significa que su sistema no tiene espacio de intercambio disponible actualmente.

      Puede verificar que no haya intercambio activo con la utilidad free:

      Output

      total used free shared buff/cache available Mem: 981Mi 122Mi 647Mi 0.0Ki 211Mi 714Mi Swap: 0B 0B 0B

      Como puede ver en la fila de Swap de los resultados, no existe intercambio activo en el sistema.

      Paso 2: Comprobar el espacio disponible en la partición de la unidad de disco duro

      Antes de crear nuestro archivo de intercambio, comprobaremos la utilización actual de nuestro disco para asegurarnos de contar con espacio suficiente. Realice esto ingresando lo siguiente:

      Output

      Filesystem Size Used Avail Use% Mounted on udev 474M 0 474M 0% /dev tmpfs 99M 932K 98M 1% /run /dev/vda1 25G 1.4G 23G 7% / tmpfs 491M 0 491M 0% /dev/shm tmpfs 5.0M 0 5.0M 0% /run/lock tmpfs 491M 0 491M 0% /sys/fs/cgroup /dev/vda15 105M 3.9M 101M 4% /boot/efi /dev/loop0 55M 55M 0 100% /snap/core18/1705 /dev/loop1 69M 69M 0 100% /snap/lxd/14804 /dev/loop2 28M 28M 0 100% /snap/snapd/7264 tmpfs 99M 0 99M 0% /run/user/1000

      El dispositivo con / en la columna Mounted on es nuestro disco en este caso. En este ejemplo, contamos con bastante espacio disponible (solo 1.4 GB utilizados). Probablemente su uso será diferente.

      Aunque existen varias opiniones acerca de la dimensión adecuada de un espacio de intercambio, depende de sus preferencias personales y de los requisitos de su aplicación. En general, una cantidad idéntica o equivalente al doble de la cantidad de RAM en su sistema es un buen punto de partida. Otra buena regla general es que cualquier cosa que supere los 4G de intercambio es probablemente innecesaria si lo está utilizando como una segunda opción al RAM.

      Paso 3: Creación de un archivo de intercambio

      Ahora que conocemos nuestro espacio de disco duro disponible, podemos crear un archivo de intercambio en nuestro sistema de archivos. Asignaremos un archivo del tamaño que deseemos y lo llamaremos swapfile en nuestro directorio root (/).

      La mejor opción para crear un archivo de intercambio es usar el programa fallocate. Este comando crea instantáneamente un archivo del tamaño especificado.

      Dado que el servidor de nuestro ejemplo tiene 1 G de RAM, crearemos un archivo de 1 G en esta guía. Ajuste esto para satisfacer las necesidades de su propio servidor:

      • sudo fallocate -l 1G /swapfile

      Podemos verificar que la cantidad correcta de espacio estaba reservada ingresando lo siguiente:

      • -rw-r--r-- 1 root root 1.0G Apr 25 11:14 /swapfile

      Nuestro archivo se ha creado con la cantidad correcta de espacio reservado.

      Paso 4: Habilitación del archivo de intercambio

      Ahora que tenemos un archivo del tamaño correcto disponible, debemos convertir esto en espacio de intercambio.

      Primero, debemos restringir los permisos del archivo para que solo los usuarios con privilegios de root puedan leer el contenido. Esto impide que usuarios comunes puedan acceder al archivo, lo que tendría implicaciones de seguridad significativas.

      Ingrese lo siguiente para que solo root pueda acceder al archivo:

      Verifique el cambio de permisos introduciendo lo siguiente:

      Output

      -rw------- 1 root root 1.0G Apr 25 11:14 /swapfile

      Como puede ver, los indicadores de lectura y escritura solo están habilitados para el root user.

      Ahora podemos marcar el archivo como espacio de intercambio al ingresar lo siguiente:

      Output

      Setting up swapspace version 1, size = 1024 MiB (1073737728 bytes) no label, UUID=6e965805-2ab9-450f-aed6-577e74089dbf

      Después de marcar el archivo, podemos habilitar el archivo de intercambio, lo cual permite que nuestro sistema empiece a utilizarlo:

      Verifique que el intercambio esté disponible ingresando lo siguiente:

      Output

      NAME TYPE SIZE USED PRIO /swapfile file 1024M 0B -2

      Podemos verificar los resultados de la utilidad free de nuevo para corroborar nuestros hallazgos:

      Output

      total used free shared buff/cache available Mem: 981Mi 123Mi 644Mi 0.0Ki 213Mi 714Mi Swap: 1.0Gi 0B 1.0Gi

      Nuestro intercambio se ha configurado con éxito y nuestro sistema operativo comenzará a utilizarlo según sea necesario.

      Paso 5: Lograr que el archivo de intercambio sea permanente

      Nuestros cambios recientes habilitaron el archivo de intercambio para la sesión en curso. Sin embargo, si reiniciamos, el servidor no conservará los ajustes de intercambio de forma automática. Podemos cambiar esto añadiendo el archivo de intercambio a nuestro archivo /etc/fstab.

      Respalde el archivo /etc/fstab en caso de que algún imprevisto:

      • sudo cp /etc/fstab /etc/fstab.bak

      Añada la información del archivo de intercambio al final de su archivo /etc/fstab ingresando lo siguiente:

      • echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

      A continuación, revisaremos algunos ajustes que podamos actualizar para regular nuestro espacio de intercambio.

      Paso 6: Ajustar sus ajustes de intercambio

      Existen algunas opciones que puede configurar y que tendrán efecto en el rendimiento de su sistema al gestionar un intercambio.

      Ajuste de la propiedad “”swappiness”

      El parámetro swappiness configura la frecuencia con la cual su sistema intercambia datos de la RAM al espacio de intercambio. Este es un valor entre 0 y 100 que representa un porcentaje.

      Con valores cercanos a cero, el núcleo no intercambiará datos en el disco a menos que sea absolutamente necesario. Recuerde que las interacciones con el archivo de intercambio son “exigentes” puesto que tardan mucho más que las interacciones con la RAM y pueden reducir el rendimiento considerablemente. Indicar al sistema que no dependa del intercambio en demasía hará que sea más rápido.

      En un esfuerzo por mantener más espacio de RAM libre, se intentará verter al intercambio más datos de los valores cercanos a 100. Dependiendo del perfil de memoria de sus aplicaciones o para qué está utilizando su servidor, esto podría ser mejor en algunos casos.

      Podemos ver el valor de intercambiabilidad actual al ingresar lo siguiente:

      • cat /proc/sys/vm/swappiness

      Output

      60

      Para un escritorio, un ajuste de intercambiabilidad de 60 no es un mal valor. Para un servidor, posiblemente le convenga acercarlo a 0.

      Podemos fijar la capacidad de intercambio en un valor diferente con el comando sysctl.

      Por ejemplo, para establecer la intercambiabilidad en 10, podríamos ingresar lo siguiente:

      • sudo sysctl vm.swappiness=10

      Output

      vm.swappiness = 10

      Esta configuración persistirá hasta el próximo reinicio. Podemos establecer este valor automáticamente en el reinicio añadiendo la línea a nuestro archivo /etc/sysctl.conf:

      • sudo nano /etc/sysctl.conf

      En la parte inferior, puede añadir:

      /etc/sysctl.conf

      vm.swappiness=10
      

      Guarde y cierre el archivo cuando haya terminado.

      Ajustar la configuración de presión de caché

      Otro valor relacionado que podría querer modificar es el vfs_cache_pressure. Esta ajuste determina en qué medida el sistema elegirá almacenar en caché información de inodos y entradas de directorio en lugar de otros datos.

      Básicamente, estos son datos de acceso sobre el sistema de archivos. Generalmente, la búsqueda de esto supone costos muy altos y se solicita con mucha frecuencia, por lo cual el almacenamiento en caché . Puede ver el valor actual consultando el sistema de archivos proc nuevamente:

      • cat /proc/sys/vm/vfs_cache_pressure

      Output

      100

      Dado que está configurado actualmente, nuestro sistema elimina la información de inodo de la memoria caché demasiado rápido. Podemos establecer esto en un parámetro más conservador como 50 al ingresar:

      • sudo sysctl vm.vfs_cache_pressure=50

      Output

      vm.vfs_cache_pressure = 50

      Una vez más, esto solo es válido para nuestra sesión actual. Podemos cambiar eso añadiéndolo en nuestro archivo de configuración como hicimos con nuestro ajuste de intercambiabilidad:

      • sudo nano /etc/sysctl.conf

      En la parte inferior, añada la línea que especifique su nuevo valor:

      /etc/sysctl.conf

      vm.vfs_cache_pressure=50
      

      Guarde y cierre el archivo cuando haya terminado.

      Conclusión

      Seguir los pasos de esta guía le brindará un respiro en casos en los que podrían generarse excepciones por falta de memoria. El espacio de intercambio puede ser increíblemente útil para evitar algunos de estos problemas comunes.

      Si encuentra errores de falta de memoria (OOM) u observa que su sistema no puede utilizar las aplicaciones que necesita, la mejor solución es optimizar sus configuraciones de aplicaciones o actualizar su servidor.



      Source link

      Cómo agregar prueba de unidades a su proyecto de Django


      El autor seleccionó a Open Internet/Free Speech Fund para recibir una donación como parte del programa Write for DOnations.

      Introducción

      Es casi imposible crear sitios web que desde el principio funcionen a la perfección y no tengan errores. Por ese motivo, debe probar su aplicación web para encontrar esos errores y trabajar en ellos de forma proactiva. Para mejorar la eficiencia de las pruebas, es común desglosarlas en unidades que prueben funcionalidades específicas de la aplicación web. Esta práctica se denomina prueba de unidades. Hace que sea más fácil detectar errores, dado que las pruebas se centran en pequeñas partes (unidades) de su proyecto independientemente de otras.

      Probar un sitio web puede ser una tarea compleja, ya que consta de varias capas de lógica, como la gestión de solicitudes HTTP, la validación de formularios y la representación de plantillas. Sin embargo, Django ofrece un conjunto de herramientas que le permite probar su aplicación web sin problemas. Aunque es posible utilizar otros marcos de pruebas, la opción preferida para escribir pruebas en Django es usar el módulo unittest de Python.

      A través de este tutorial, configurará un conjunto de pruebas en su proyecto de Django y escribirá pruebas de unidades para los modelos y vistas de su aplicación. Ejecutará estas pruebas, analizará sus resultados y aprenderá a encontrar las causas de errores en las pruebas que fallan.

      Requisitos previos

      Antes de iniciar este tutorial, necesitará lo siguiente:

      Paso 1: Agregar un conjunto de pruebas a su aplicación en Django

      Un conjunto de pruebas en Django es una colección de todos los casos de prueba en todas las aplicaciones de su proyecto. Para lograr que la utilidad de prueba de Django descubra los casos de prueba que tiene, se escriben los casos de prueba en secuencias de comandos cuyos nombres comiencen con test. En este paso, creará la estructura del directorio y los archivos para su conjunto de pruebas, y creará un caso de prueba vacío dentro de él.

      Si siguió la serie de tutoriales Desarrollo en Django, tendrá una aplicación de Django denominada blogsite.

      Crearemos una carpeta para contener todos nuestros scripts de prueba. Primero, active el entorno virtual:

      • cd ~/my_blog_app
      • . env/bin/activate

      Luego, diríjase al directorio de la aplicación blogsite, la carpeta que contiene los archivos models.py y views.py, y luego cree una carpeta nueva llamada tests:

      • cd ~/my_blog_app/blog/blogsite
      • mkdir tests

      A continuación, convertirá esta carpeta en un paquete Python; agregue un archivo __init__.py:

      • cd ~/my_blog_app/blog/blogsite/tests
      • touch __init__.py

      Ahora, agregue un archivo para probar sus modelos y otro para probar sus vistas:

      • touch test_models.py
      • touch test_views.py

      Por último, creará un caso de prueba vacío en test_models.py. Deberá importar la clase TestCase de Django y hacer que sea una súper clase de su propia clase de caso de prueba. Más adelante, añadirá métodos a este caso de prueba para probar la lógica en sus modelos. Abra el archivo test_models.py​​​1​​​:

      Luego, añada el siguiente código al archivo:

      ~/my_blog_app/blog/blogsite/tests/test_models.py

      from django.test import TestCase
      
      class ModelsTestCase(TestCase):
          pass
      

      De esta manera, habrá añadido correctamente un conjunto de pruebas a la aplicación blogsite. Luego, completará los detalles del caso de prueba de modelo vacío que creó aquí.

      Paso 2: Probar su código Python

      En este paso, probará la lógica del código escrito en el archivo models.py. En particular, probará el método save del modelo Post para asegurarse de que cree el slug correcto del título de una entrada cuando se invoque.

      En este caso, comenzaremos observando el código que ya tiene en su archivo models.py para ver el método save del modelo Post:

      • cd ~/my_blog_app/blog/blogsite
      • nano models.py

      Observará lo siguiente:

      ~/my_blog_app/blog/blogsite/models.py

      class Post(models.Model):
          ...
          def save(self, *args, **kwargs):
              if not self.slug:
                  self.slug = slugify(self.title)
              super(Post, self).save(*args, **kwargs)
          ...
      

      Podemos ver que verifica si la entrada que está a punto de guardar tiene un valor slug, y, si no, invoca a slugify a fin de crear un valor slug para la misma. Este es el tipo de lógica que tal vez quiera probar para asegurarse de que los slugs se creen en realidad cuando se guarde una entrada.

      Cierre el archivo.

      Para probar esto, regrese a test_models.py:

      Luego, actualícelo para que se vea como a continuación y agregue las porciones resaltadas:

      ~/my_blog_app/blog/blogsite/tests/test_models.py

      from django.test import TestCase
      from django.template.defaultfilters import slugify
      from blogsite.models import Post
      
      
      class ModelsTestCase(TestCase):
          def test_post_has_slug(self):
              """Posts are given slugs correctly when saving"""
              post = Post.objects.create(title="My first post")
      
              post.author = "John Doe"
              post.save()
              self.assertEqual(post.slug, slugify(post.title))
      

      Este nuevo método test_post_has_slug crea una nueva entrada con el título "My first post" y, luego, atribuye a esta un autor y la guarda. Después de esto, usando el método assertEqual del módulo unittest de Python, se comprueba si el slug de la entrada es correcto. El método assertEqual verifica si los dos argumentos que se le pasan son iguales, como lo determina el operador "==", y genera un error si no lo son.

      Guarde y cierre test_models.py.

      Este es un ejemplo de lo que se puede probar. Cuanta más lógica añada a su proyecto, habrá más por probar. Si añade más lógica al método save o crea nuevos métodos para el modelo Post, querrá añadir más pruebas aquí. Usted puede añadirlas al método test_post_has_slug o crear nuevos métodos de prueba, pero sus nombres deben comenzar con test.

      Creó con éxito un caso de prueba para el modelo Post, en el que validó que los slugs se crean correctamente después del guardado. En el siguiente paso, escribirá un caso de prueba para probar las vistas.

      Paso 3: Usar el cliente de prueba de Django

      En este paso, escribirá un caso de prueba que probará una vista utilizando el cliente de prueba de Django. El cliente de prueba es una clase de Python que funciona como navegador web ficticio, le permite probar sus vistas e interactuar con su aplicación Django como un usuario lo haría. Puede acceder al cliente de prueba haciendo referencia a self.client en sus métodos de prueba. Por ejemplo, crearemos un caso de prueba en test_views.py. Primero, abra el archivo test_views.py:

      Luego, agregue lo siguiente:

      ~/my_blog_app/blog/blogsite/tests/test_views.py

      from django.test import TestCase
      
      
      class ViewsTestCase(TestCase):
          def test_index_loads_properly(self):
              """The index page loads properly"""
              response = self.client.get('your_server_ip:8000')
              self.assertEqual(response.status_code, 200)
      

      El ViewsTestCase contiene un método test_index_loads_properly que utiliza el cliente de prueba de Django para visitar la página principal del sitio web (http://your_server_ip:8000, donde your_server_ip es la dirección IP del servidor que utiliza). Luego, el método de prueba comprueba si la respuesta tiene un código de estado 200, lo cual significa que la página respondió sin errores. Como resultado, puede estar seguro de que cuando el usuario visite la página también responderá sin errores.

      Además del código de estado, puede leer sobre otras propiedades de la respuesta del cliente de prueba que puede probar en la página de documentación de respuestas de prueba de Django.

      En este paso, creó un caso de prueba para probar la vista que genera la página principal y verificar que funcione sin errores. Ahora, hay dos casos de prueba en su conjunto de pruebas. En el siguiente paso, los ejecutará para ver sus resultados.

      Paso 4: Ejecutar sus pruebas

      Ahora que terminó de crear un conjunto de pruebas para el proyecto, es el momento de ejecutar estas pruebas y ver sus resultados. Para ejecutar las pruebas, diríjase a la carpeta blog (que contiene el archivo manage.py de la aplicación):

      Luego, ejecútelas con lo siguiente:

      Verá un resultado similar al siguiente en su terminal:

      Output

      Creating test database for alias 'default'... System check identified no issues (0 silenced). .. ---------------------------------------------------------------------- Ran 2 tests in 0.007s OK Destroying test database for alias 'default'...

      En este resultado, hay dos puntos .., cada uno de los cuales representa un caso de prueba aprobado. Ahora, modificará test_views.py para activar una prueba que falle. Abra el archivo con lo siguiente:

      Luego, cambie el código resaltado para ver lo siguiente:

      ~/my_blog_app/blog/blogsite/tests/test_views.py

      from django.test import TestCase
      
      
      class ViewsTestCase(TestCase):
          def test_index_loads_properly(self):
              """The index page loads properly"""
              response = self.client.get('your_server_ip:8000')
              self.assertEqual(response.status_code, 404)
      

      Aquí, cambió el código de estado de 200 a 404. Ahora, ejecute la prueba de nuevo desde su directorio con manage.py:

      Verá el siguiente resultado:

      Output

      Creating test database for alias 'default'... System check identified no issues (0 silenced). .F ====================================================================== FAIL: test_index_loads_properly (blogsite.tests.test_views.ViewsTestCase) The index page loads properly ---------------------------------------------------------------------- Traceback (most recent call last): File "~/my_blog_app/blog/blogsite/tests/test_views.py", line 8, in test_index_loads_properly self.assertEqual(response.status_code, 404) AssertionError: 200 != 404 ---------------------------------------------------------------------- Ran 2 tests in 0.007s FAILED (failures=1) Destroying test database for alias 'default'...

      Verá aparecer un mensaje de error descriptivo en el que se indicará la secuencia de comandos, el caso de prueba y el método que falló. También se mostrará la causa de la falla, con un código de estado que no es igual al 404 en este caso, con el mensaje AssertionError: 200 ! = 404. El AssertionError aquí se genera en la línea de código resaltada en el archivo test_views.py:

      ~/my_blog_app/blog/blogsite/tests/test_views.py

      from django.test import TestCase
      
      
      class ViewsTestCase(TestCase):
          def test_index_loads_properly(self):
              """The index page loads properly"""
              response = self.client.get('your_server_ip:8000')
              self.assertEqual(response.status_code, 404)
      

      Le indica que la afirmación es falsa, es decir, el código de estado de respuesta (200) no es lo que se esperaba (404). Precediendo el mensaje de error, puede ver que los dos puntos .. pasaron a ser . F, lo cual indica que el primer caso de prueba se aprobó mientras que el segundo no.

      Conclusión

      A través de este tutorial, creó un conjunto de pruebas en su proyecto de Django, añadió casos de prueba para probar el modelo y la lógica de visualización, aprendió a ejecutar pruebas y analizó el resultado de una prueba. Como siguiente paso, puede crear nuevas secuencias de comandos para código Python que no estén en models.py y views.py.

      A continuación, consulte algunos artículos que pueden ser útiles al crear y probar sitios web con Django:

      También puede consultar nuestra página de temas de Django para ver tutoriales y proyectos adicionales.



      Source link

      Cómo agregar Sidekiq y Redis a una aplicación de Ruby on Rails


      Introducción

      Al desarrollar una aplicación de Ruby on Rails, es posible que encuentre tareas de aplicación que se deben realizar de forma asíncrona. El procesamiento de datos, el envío de correos electrónicos por lotes o la interacción con API externas son ejemplos de trabajo que se pueden realizar de forma asincrónica con tareas en segundo plano. Con tareas en segundo plano, puede mejorar el rendimiento de su aplicación descargando tareas que pueden demandar gran cantidad de tiempo a una cola de procesamiento en segundo plano y, así, liberar el ciclo de solicitud o respuesta original

      Sidekiq es uno de los marcos de tareas en segundo plano más utilizados que se pueden implementar en una aplicación de Rails. Cuenta con el respaldo de Redis, un sistema de almacenamiento de clave-valor en memoria, conocido por su flexibilidad y rendimiento. Sidekiq utiliza Redis como almacén de administración de tareas para procesar miles de tareas por segundo.

      En este tutorial, agregaremos Redis y Sidekiq a una aplicación de Rails existente. Crearemos un conjunto de clases y métodos de trabajadores de Sidekiq para gestionar lo siguiente:

      • Una carga en lote de información sobre tiburones en peligro a la base de datos de aplicación desde un archivo CSV en el repositorio del proyecto.
      • La eliminación de estos datos.

      Cuando haya terminado, tendrá una aplicación de muestra que utilizará trabajadores y tareas para procesar tareas de forma asíncrona. Esta será una buena base para añadir trabajadores y trabajos a su aplicación utilizando este tutorial como punto de partida.

      Requisitos previos

      Para este tutorial, necesitará lo siguiente:

      Paso 1: Clonar el proyecto e instalar dependencias

      Nuestro primer paso será clonar el repositorio de rails-bootstrap de la cuenta de GitHub comunitaria de DigitalOcean. En este repositorio se incluye el código de la configuración descrita en el artículo Cómo agregar Bootstrap a una aplicación de Ruby on Rails, en el que se explica la forma de añadir Bootstrap a un proyecto de Rails 5 existente.

      Clone el repositorio en un directorio llamado rails-sidekiq:

      • git clone https://github.com/do-community/rails-bootstrap.git rails-sidekiq

      Diríjase al directorio rails-sidekiq:

      Para trabajar con el código, primero deberá instalar las dependencias del proyecto que se enumeran en el Gemfile de este. También deberá añadir la gema sidekiq al proyecto para trabajar con Sidekiq y Redis.

      Abra el archivo de Gemfile del proyecto para editarlo con nano o su editor favorito:

      Añada la gema en cualquier punto de las dependencias del proyecto principal (encima de las dependencias de desarrollo):

      ~/rails-sidekiq/Gemfile

      . . .
      # Reduces boot times through caching; required in config/boot.rb
      gem 'bootsnap', '>= 1.1.0', require: false
      gem 'sidekiq', '~>6.0.0'
      
      group :development, :test do
      . . .
      

      Guarde y cierre el archivo cuando termine de añadir la gema.

      Utilice el siguiente comando para instalar las gemas:

      Veremos en el resultado que la gema de redis también se instala como requisito para sidekiq.

      Luego, instalará sus dependencias de Yarn. Debido a que este proyecto de Rails 5 se modificó para proporcionar recursos con webpack, Yarn ahora gestiona sus dependencias de JavaScript. Esto significa que es necesario instalar y verificar las dependencias que se enumeran en el archivo package.json del proyecto.

      Ejecute yarn install para instalar estas dependencias:

      Luego, ejecute las migraciones de su base de datos:

      Una vez que hayan terminado sus migraciones, puede probar la aplicación para asegurarse de que funcione como se espera. Inicie su servidor en el contexto de su paquete local con el siguiente comando si trabaja a nivel local:

      Si trabaja en un servidor de desarrollo, puede iniciar la aplicación con lo siguiente:

      • bundle exec rails s --binding=your_server_ip

      Diríjase a localhost:3000 o http://your_server_ip:3000. Visualizará la siguiente página de destino:

      Página de inicio de la aplicación

      Para crear un nuevo tiburón, haga clic en el botón Get Shark Info, que lo dirigirá a la ruta sharks/index:

      Ruta del índice de tiburones

      Para verificar que la aplicación funcione, podemos añadirle información de prueba. Haga clic en New Shark. Gracias a la configuración de autenticación del proyecto, se le solicitará un nombre de usuario (sammy) y una contraseña (tiburón).

      En la página New Shark, ingrese “Gran tiburón blanco” en el campo Name y “Terrorífico” en el campo Facts.

      Creación de un tiburón

      Haga clic en el botón Create Shark para crear el tiburón. Una vez que haya creado el tiburón, podrá detener el servidor con CTRL+C.

      Con esto, habrá instalado las dependencias necesarias para su proyecto y comprobado que funciona. Luego, puede realizar algunos cambios en la aplicación de Rails para trabajar con sus recursos relacionados con los tiburones en peligro.

      Paso 2: Generar un controlador para recursos relacionados con tiburones en peligro

      Para trabajar con nuestros recursos relacionados con tiburones en peligro, añadiremos un nuevo modelo a la aplicación y un controlador que regulará la manera en que se presente a los usuarios la información sobre tiburones en peligro. Nuestro objetivo final es permitir que los usuarios carguen un gran lote de información sobre tiburones en peligro, sin bloquear la función general de nuestra aplicación, y eliminen dicha información cuando ya no la necesiten.

      Primero, crearemos un modelo Endangered para nuestros tiburones en peligro. Incluiremos un campo de cadena a la tabla de nuestra base de datos para el nombre del tiburón y otro campo de cadena para las categorías de la Unión Internacional para la Conservación de la Naturaleza (UICN) que determinan el grado de riesgo en el que se encuentra cada tiburón.

      En última instancia, la estructura de nuestro modelo coincidirá con las columnas del archivo CSV que usaremos para crear nuestra carga en lote. Este archivo se encuentra en el directorio db y puede verificar su contenido con el siguiente comando:

      El archivo contiene una lista de 73 tiburones en peligro y sus situaciones según la IUCN: vu significa vulnerable, en significa en peligro y cr significa en peligro crítico.

      Nuestro modelo Endangered se correlacionará con estos datos, lo que nos permitirá crear nuevas instancias de Endangered desde este archivo CSV. Cree el modelo con el siguiente comando:

      • rails generate model Endangered name:string iucn:string

      Luego, genere un controlador Endangered con una acción index:

      • rails generate controller endangered index

      Esto nos proporcionará un punto de partida para crear la función de nuestra aplicación, aunque también tendremos que añadir métodos personalizados al archivo del controlador que Rails generó para nosotros.

      Abra el archivo ahora:

      • nano app/controllers/endangered_controller.rb

      Rails nos proporciona un esquema de borrador que podemos comenzar a completar.

      Primero, debemos determinar las rutas que necesitamos para trabajar con nuestros datos. Gracias al comando generate controller​​​​​​, contamos con un mé todo index para comenzar. Esto se correlacionará con una vista de index, en la que presentaremos a los usuarios la opción para cargar tiburones en peligro.

      Sin embargo, también nos convendrá tratar los casos en los que los usuarios ya hayan cargado tiburones; no necesitarán una opción de carga en este caso. De alguna forma, tendremos que evaluar la cantidad existente de casos de la clase Endangered, puesto que más de una indica que ya se produjo la carga del lote.

      Empecemos creando un método set_endangered private​​​ que tomará cada instancia de nuestra clase Endangered de la base de datos. Añada el siguiente código al archivo:

      ~/rails-sidekiq/app/controllers/endangered_controller.rb

      class EndangeredController < ApplicationController
        before_action :set_endangered, only: [:index, :data]
      
        def index
        end
      
        private
      
          def set_endangered
            @endangered = Endangered.all
          end
      
      end
      

      Tenga en cuenta que el filtro before_action garantizará que el valor de @endangered solo esté configurado para las rutas index y data, donde gestionaremos los datos de tiburones en peligro.

      Después, añada el siguiente código al método index a fin de determinar la ruta correcta para los usuarios que visitan esta parte de la aplicación:

      ~/rails-sidekiq/app/controllers/endangered_controller.rb

      class EndangeredController < ApplicationController
        before_action :set_endangered, only: [:index, :data]
      
        def index          
          if @endangered.length > 0
            redirect_to endangered_data_path
          else
            render 'index'
          end
        end
      . . .
      

      Si hay más de 0 instancias de nuestra clase Endangered, redirigiremos a los usuarios a la ruta data, donde podrán ver información sobre los tiburones que crearon. De lo contrario, verán la vista de index.

      Luego, debajo del método index, añada un método data, que se correlacionará con una vista de data:

      ~/rails-sidekiq/app/controllers/endangered_controller.rb

      . . .
        def index          
          if @endangered.length > 0
            redirect_to endangered_data_path
          else
            render 'index'
          end
        end
      
        def data
        end
      . . .
      

      A continuación, añadiremos un método para gestionar la carga de datos. Llamaremos a este método upload e invocará una clase y método de trabajador Sidekiq para realizar la carga de datos desde el archivo CSV. En el siguiente paso, crearemos la definición de esta clase de trabajador: AddEndangeredWorker.

      Por ahora, añada el siguiente código al archivo para invocar al trabajador Sidekiq y realizar la carga:

      ~/rails-sidekiq/app/controllers/endangered_controller.rb

      . . .
        def data
        end
      
        def upload
          csv_file = File.join Rails.root, 'db', 'sharks.csv'   
          AddEndangeredWorker.perform_async(csv_file)
          redirect_to endangered_data_path, notice: 'Endangered sharks have been uploaded!'
        end
      . . .
      

      Al invocar el método perform_async en la clase AddEndangeredWorker usando el archivo CSV como argumento, este código garantiza que los datos de tiburones y la tarea de carga se transfieran a Redis. Los trabajadores Sidekiq que configuraremos monitorean la cola de trabajo y responderán cuando surjan nuevos trabajo.

      Después de invocar perform_async, nuestro método upload​​​ aplica redireccionamiento a la ruta data, en la que los usuarios podrán ver los tiburones cargados.

      Luego, añadiremos un método destroy para destruir los datos. Añada el siguiente código que está debajo del método upload:

      ~/rails-sidekiq/app/controllers/endangered_controller.rb

      . . .
        def upload
          csv_file = File.join Rails.root, 'db', 'sharks.csv'   
          AddEndangeredWorker.perform_async(csv_file)
          redirect_to endangered_data_path, notice: 'Endangered sharks have been uploaded!'
        end
      
        def destroy
          RemoveEndangeredWorker.perform_async
          redirect_to root_path
        end
      . . .
      

      Al igual que nuestro método upload, nuestro método destroy incluye la invocación de perform_async en una clase RemoveEndangeredWorker: el otro trabajador Sidekiq que crearemos. Después de invocar este método, redirecciona a los usuarios a la ruta de la aplicación root.

      El archivo terminado tendrá este aspecto:

      ~/rails-sidekiq/app/controllers/endangered_controller.rb

      class EndangeredController < ApplicationController
        before_action :set_endangered, only: [:index, :data]
      
        def index          
          if @endangered.length > 0
            redirect_to endangered_data_path
          else
            render 'index'
          end
        end
      
        def data
        end
      
        def upload
          csv_file = File.join Rails.root, 'db', 'sharks.csv'   
          AddEndangeredWorker.perform_async(csv_file)
          redirect_to endangered_data_path, notice: 'Endangered sharks have been uploaded!'
        end
      
        def destroy
          RemoveEndangeredWorker.perform_async
          redirect_to root_path
        end
      
        private
      
          def set_endangered
            @endangered = Endangered.all
          end
      
      end
      

      Guarde y cierre el archivo cuando concluya la edición.

      Como paso final para afianzar las rutas de nuestra aplicación, modificaremos el código de config/routes.rb, el archivo en el que residen nuestras instrucciones de ruta.

      Abra el archivo ahora:

      El archivo actualmente tiene este aspecto:

      ~/rails-sidekiq/config/routes.rb

      Rails.application.routes.draw do
        get 'endangered/index'
        get 'home/index'
        resources :sharks do
                resources :posts
        end
        root 'home#index'
        # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
      end
      

      Será necesario actualizar el archivo para incluir las rutas que definimos en nuestro controlador: data, upload y destroy. Nuestra ruta data coincidirá con una solicitud GET para obtener los datos de tiburones, mientras que nuestras rutas upload y destroy se asignarán a las solicitudes POST que cargan y destruyen esos datos.

      Añada el siguiente código al archivo para definir estas rutas:

      ~/rails-sidekiq/config/routes.rb

      Rails.application.routes.draw do
        get 'endangered/index'
        get 'endangered/data', to: 'endangered#data'
        post 'endangered/upload', to: 'endangered#upload'
        post 'endangered/destroy', to: 'endangered#destroy'
        get 'home/index'
        resources :sharks do
                resources :posts
        end
        root 'home#index'
        # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
      end
      

      Guarde y cierre el archivo cuando concluya la edición.

      Con su modelo y controlador Endangered, ahora puede proceder a definir sus clases de trabajadores Sidekiq.

      Paso 3: Definir trabajadores Sidekiq

      Invocamos los métodos perform_async en nuestros trabajadores Sidekiq de nuestro controlador, pero aún debemos crear los trabajadores.

      Primero, cree un directorio workers para los trabajadores:

      Abra un archivo para el trabajador AddEndangeredWorker:

      • nano app/workers/add_endangered_worker.rb

      En este archivo, añadiremos el código que nos permitirá trabajar con los datos de nuestro archivo CSV. Primero, añada el código al archivo que creará la clase, incluya la biblioteca CSV Ruby y asegúrese que esta clase funcione como trabajador Sidekiq:

      ~/rails-sidekiq/app/workers/add_endangered_worker.rb

      class AddEndangeredWorker
        require 'csv'
        include Sidekiq::Worker
        sidekiq_options retry: false
      
      end
      

      También incluiremos la opción retry:false para garantizar que Sidekiq no vuelva a intentar realizar la carga ante una falla.

      Luego, añada el código para la función perform:

      ~/rails-sidekiq/app/workers/add_endangered_worker.rb

      class AddEndangeredWorker
        require 'csv'
        include Sidekiq::Worker
        sidekiq_options retry: false
      
        def perform(csv_file)
          CSV.foreach(csv_file, headers: true) do |shark|
          Endangered.create(name: shark[0], iucn: shark[1])
        end
       end
      
      end
      

      El método perform recibe los argumentos del método perform_async definido en el controlador, por lo que es importante que los valores de argumento estén nivelados. Aquí, pasamos en csv_file, la variable que definimos en el controlador y usamos el método foreach de la biblioteca CSV para leer los valores del archivo. Configurar headers:true para este bucle garantiza que se trate a la primera fila del archivo como a una fila de encabezados.

      Luego, el bloque luego lee los valores del archivo en las columnas que configuramos para nuestro modelo Endangered: name e iucn. Ejecutar este bucle creará instancias de Endangered para cada una de las entradas de nuestro archivo CSV.

      Una vez que finalice la edición, guarde y cierre el archivo.

      Luego, crearemos un trabajador para que elimine estos datos. Abra un archivo para la clase RemoveEndangeredWorker:

      • nano app/workers/remove_endangered_worker.rb

      Añada el código para definir la clase y para garantizar que utilice la biblioteca CSV y las funciones como un trabajador Sidekiq:

      ~/rails-sidekiq/app/workers/remove_endangered_worker.rb

      class RemoveEndangeredWorker
        include Sidekiq::Worker
        sidekiq_options retry: false
      
      end
      

      Luego, añada un método perform para gestionar la destrucción de los datos de tiburones en peligro:

      ~/rails-sidekiq/app/workers/remove_endangered_worker.rb

      class RemoveEndangeredWorker
        include Sidekiq::Worker
        sidekiq_options retry: false
      
        def perform
          Endangered.destroy_all
        end
      
      end
      

      El método perform invoca a destroy_all en la clase Endangered, que eliminará todas las instancias de esa clase de la base de datos.

      Guarde y cierre el archivo cuando concluya la edición.

      Una vez que sus trabajadores estén activos, podrá proceder a crear un diseño para sus vistas de endangered, así como plantillas para sus vistas de index y data, para que los usuarios puedan cargar y ver tiburones en peligro.

      Paso 4: Agregar diseños y plantillas de vistas

      Para que los usuarios disfruten de su propia información de tiburones en peligro, tendremos que abordar dos aspectos: el diseño de las vistas definidas en nuestro controlador endangered y las plantillas de vista de las vistas de index y data.

      Actualmente, nuestra aplicación utiliza un diseño integral, ubicado en app/views/layouts/application.html.erb, uno parcial de navegación y uno para las vistas de sharks. El diseño de la aplicación busca un bloque de contenido, que nos permite cargar diferentes diseños basados en la parte de la aplicación con la que nuestro usuario interactúa: para la página home​​​ index, este verá un diseño y para cualquier vista que se relacione con tiburones individuales verá otro.

      Podemos reutilizar el diseño de sharks para nuestras vistas de endangered, ya que este formato también funcionará para presentar datos de tiburones de forma masiva.

      Copie el archivo de diseño de sharks para crear un diseño de endangered:

      • cp app/views/layouts/sharks.html.erb app/views/layouts/endangered.html.erb

      Luego, trabajaremos en crear las plantillas de vista para nuestras vistas de index y data.

      Abra la plantilla index primero:

      • nano app/views/endangered/index.html.erb

      Elimine el código estándar y añada en su lugar el siguiente código, que proporcionará a los usuarios información general sobre las categorías en peligro y les dará la opción de cargar información sobre tiburones en peligro:

      ~/rails-sidekiq/app/views/endangered/index.html.erb

      <p id="notice"><%= notice %></p>
      
      <h1>Endangered Sharks</h1>
      
      <p>International Union for Conservation of Nature (ICUN) statuses: <b>vu:</b> Vulnerable, <b>en:</b> Endangered, <b>cr:</b> Critically Endangered </p>
      
      <br>
      
        <%= form_tag endangered_upload_path do %>
        <%= submit_tag "Import Endangered Sharks" %>
        <% end %>
      
        <br>
      
      <%= link_to 'New Shark', new_shark_path, :class => "btn btn-primary btn-sm" %> <%= link_to 'Home', home_index_path, :class => "btn btn-primary btn-sm" %>
      

      Un form_tag hace posible la carga de datos al apuntar una acción posterior a endangered_upload_path, la ruta que definimos para nuestras cargas. El botón de envío, creado con submit_tag, solicita a los usuarios a “Import Endangered Sharks”.

      Además de este código, incluimos información general sobre códigos de ICUN, para que los usuarios puedan interpretar los datos que verán.

      Guarde y cierre el archivo cuando concluya la edición.

      Luego, abra un archivo para la vista de data:

      • nano app/views/endangered/data.html.erb

      Añada el siguiente código, que agregará una tabla con los datos de tiburones en peligro:

      ~/rails-sidekiq/app/views/endangered/data.html.erb

      <p id="notice"><%= notice %></p>
      
      <h1>Endangered Sharks</h1>
      
      <p>International Union for Conservation of Nature (ICUN) statuses: <b>vu:</b> Vulnerable, <b>en:</b> Endangered, <b>cr:</b> Critically Endangered </p>
      
      <div class="table-responsive">
      <table class="table table-striped table-dark">
        <thead>
          <tr>
            <th>Name</th>
            <th>IUCN Status</th>
            <th colspan="3"></th>
          </tr>
        </thead>
      
        <tbody>
          <% @endangered.each do |shark| %>
            <tr>
              <td><%= shark.name %></td>
              <td><%= shark.iucn %></td>
            </tr>
          <% end %>
        </tbody>
      </table>
      </div>
      
      <br>
      
        <%= form_tag endangered_destroy_path do %>
        <%= submit_tag "Delete Endangered Sharks" %>
        <% end %>
      
        <br>
      
      <%= link_to 'New Shark', new_shark_path, :class => "btn btn-primary btn-sm" %> <%= link_to 'Home', home_index_path, :class => "btn btn-primary btn-sm" %>
      

      Este código incluye de nuevo los códigos de estado de la ICUN y una tabla de Bootstrap para los datos emitidos. Al recorrer nuestra variable @endangered, mostramos el nombre y la situación de cada tiburón según la ICUN en la tabla.

      Debajo de la tabla, tenemos otro conjunto de form_tags y submit_tags, que se publican a la ruta destroy ofreciendo a los usuarios la opción de "Delete Endangered Sharks”.

      Guarde y cierre el archivo cuando concluya la edición.

      La última modificación que aplicaremos a nuestras vistas se hará en la vista de index asociada con nuestro controlador home. Como podrá recordar, esta vista se configura como root de la aplicación en config/routes.rb.

      Abra este archivo para editarlo:

      • nano app/views/home/index.html.erb

      Encuentre la columna en la fila Sharks are ancient:

      ~/rails-sidekiq/app/views/home/index.html.erb

      . . .
              <div class="col-lg-6">
                  <h3>Sharks are ancient</h3>
                  <p>There is evidence to suggest that sharks lived up to 400 million years ago.
                  </p>
              </div>
          </div>
      </div>
      

      Añada el siguiente código al archivo:

      ~/rails-sidekiq/app/views/home/index.html.erb

      . . .
              <div class="col-lg-6">
                  <h3>Sharks are ancient and SOME are in danger</h3>
                  <p>There is evidence to suggest that sharks lived up to 400 million years ago. Without our help, some could disappear soon.</p>
                  <p><%= button_to 'Which Sharks Are in Danger?', endangered_index_path, :method => :get,  :class => "btn btn-primary btn-sm"%>
                  </p>
              </div>
          </div>
      </div>
      

      Incluimos un llamado a la acción para que los usuarios aprendan más sobre tiburones en peligro compartiendo, primero, un mensaje fuerte y, luego, añadiendo un asistente button_to que envía una solicitud GET a nuestra ruta index endangered y permite que los usuarios accedan a esa parte de la aplicación. Desde allí, podrán cargar y ver información de tiburones en peligro.

      Guarde y cierre el archivo cuando concluya la edición.

      Una vez que esté listo su código, estará preparado para iniciar la aplicación y cargar algunos tiburones.

      Paso 5: Iniciar Sidekiq y probar la aplicación

      Antes de iniciar la aplicación, necesitaremos ejecutar migraciones en nuestra base de datos e iniciar Sidekiq para habilitar nuestros trabajadores. Redis ya se debería estar ejecutando en el servidor, pero podemos verificarlo para estar seguros. Una vez que hagamos todo esto, estaremos listos para probar la aplicación.

      Primero, verifique que Redis esté en ejecución:

      Debería ver un resultado como el siguiente:

      Output

      ● redis-server.service - Advanced key-value store Loaded: loaded (/lib/systemd/system/redis-server.service; enabled; vendor preset: enabled) Active: active (running) since Tue 2019-11-12 20:37:13 UTC; 1 weeks 0 days ago

      Luego, ejecute las migraciones de su base de datos:

      Ahora puede iniciar Sidekiq en el contexto de su paquete de proyectos actual usando el comando bundle exec sidekiq:

      Verá un resultado como este, que indica que Sidekiq está listo para procesar tareas:

      Output

      m, `$b .ss, $$: .,d$ `$$P,d$P' .,md$P"' ,$$$$$b/md$$$P^' .d$$$$$$/$$$P' $$^' `"/$$$' ____ _ _ _ _ $: ,$$: / ___|(_) __| | ___| | _(_) __ _ `b :$$ ___ | |/ _` |/ _ |/ / |/ _` | $$: ___) | | (_| | __/ <| | (_| | $$ |____/|_|__,_|___|_|__|__, | .d$$ |_| 2019-11-19T21:43:00.540Z pid=17621 tid=gpiqiesdl INFO: Running in ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux] 2019-11-19T21:43:00.540Z pid=17621 tid=gpiqiesdl INFO: See LICENSE and the LGPL-3.0 for licensing details. 2019-11-19T21:43:00.540Z pid=17621 tid=gpiqiesdl INFO: Upgrade to Sidekiq Pro for more features and support: http://sidekiq.org 2019-11-19T21:43:00.540Z pid=17621 tid=gpiqiesdl INFO: Booting Sidekiq 6.0.3 with redis options {:id=>"Sidekiq-server-PID-17621", :url=>nil} 2019-11-19T21:43:00.543Z pid=17621 tid=gpiqiesdl INFO: Starting processing, hit Ctrl-C to stop

      Abra una segunda ventana de terminal, diríjase al directorio rails-sidekiq e inicie el servidor de aplicaciones.

      Si ejecuta la aplicación a nivel local, utilice el siguiente comando:

      Si trabaja con un servidor de desarrollo, ejecute lo siguiente:

      • bundle exec rails s --binding=your_server_ip

      Diríjase a localhost:3000 o a http://your_server_ip:3000 en el navegador. Visualizará la siguiente página de destino:

      Inicio de la aplicación de Sidekiq

      Haga clic en el botón** ¿Which Sharks Are In Danger?** . Debido a que no cargó ningún tiburón en peligro, esto lo dirigirá a la vista de endangered index:

      Vista del índice de tiburones en peligro

      Haga clic en Import Endangered Sharks para importar los tiburones. Verá un mensaje de estado que le indicará que los tiburones se importaron:

      Inicio de la importación

      También verá el comienzo de la importación. Actualice su página para ver la tabla entera:

      Actualización de tabla

      Gracias a Sidekiq, realizamos la carga del gran lote de tiburones en peligro sin cerrar el navegador ni interferir con otras funciones de la aplicación.

      Haga clic en el botón Home en la parte inferior de la página, que lo llevará de vuelta a la página principal de la aplicación:

      Inicio de la aplicación de Sidekiq

      Aquí, haga clic en Which Sharks Are in Danger? nuevamente. Esto lo llevará directamente a la vista de data, porque ya había cargado los tiburones.

      Para probar la función de eliminación, haga clic en el botón Delete Endangered Sharks que se encuentra debajo de la tabla. Una vez más, debería ser redireccionado a la página de inicio de la aplicación. Si have clic en Which Sharks Are in Danger? una última vez, lo llevará de regreso a la vista de index, en la que tendrá la opción de cargar tiburones de nuevo:

      Vista del índice de tiburones en peligro

      Su aplicación ahora se está ejecutando con los trabajadores de Sidekiq, que están listos para procesar trabajos y garantizar que los usuarios tengan una buena experiencia trabajando con su aplicación.

      Conclusión

      Ahora dispone de una aplicación Rails en funcionamiento con Sidekiq habilitado, que le permitirá descargar operaciones complejas a una cola de trabajo administrada por Sidekiq y respaldada por Redis. Esto le permitirá mejorar la velocidad y la funcionalidad de su sitio a medida que realice el desarrollo.

      Si desea obtener más información sobre Sidekiq, se recomienda comenzar consultando los docs.

      Para obtener más información sobre Redis, consulte nuestra biblioteca de recursos de Redis. También puede obtener más información sobre cómo ejecutar un clúster de Redis administrado en DigitalOcean consultando la documentación del producto.



      Source link