poder compilar el sitio con sidekiq

This commit is contained in:
f 2019-07-25 22:11:01 -03:00
parent b149374c41
commit 15b6493c08
No known key found for this signature in database
GPG key ID: 2AE5A13E321F953D
15 changed files with 38 additions and 181 deletions

View file

@ -11,7 +11,6 @@ require 'capistrano/passenger'
require 'capistrano/bundler' require 'capistrano/bundler'
require 'capistrano/rbenv' require 'capistrano/rbenv'
require 'capistrano/rails' require 'capistrano/rails'
require 'whenever/capistrano'
require 'capistrano/scm/git' require 'capistrano/scm/git'
install_plugin Capistrano::SCM::Git install_plugin Capistrano::SCM::Git

View file

@ -62,7 +62,6 @@ gem 'rugged'
gem 'sidekiq' gem 'sidekiq'
gem 'terminal-table' gem 'terminal-table'
gem 'validates_hostname' gem 'validates_hostname'
gem 'whenever', require: false
group :development, :test do group :development, :test do
gem 'pry' gem 'pry'

View file

@ -91,7 +91,6 @@ GEM
carrierwave-i18n (0.2.0) carrierwave-i18n (0.2.0)
childprocess (0.9.0) childprocess (0.9.0)
ffi (~> 1.0, >= 1.0.11) ffi (~> 1.0, >= 1.0.11)
chronic (0.10.2)
coderay (1.1.2) coderay (1.1.2)
colorator (1.1.0) colorator (1.1.0)
commonmarker (0.18.2) commonmarker (0.18.2)
@ -401,8 +400,6 @@ GEM
websocket-driver (0.7.0) websocket-driver (0.7.0)
websocket-extensions (>= 0.1.0) websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.3) websocket-extensions (0.1.3)
whenever (0.10.0)
chronic (>= 0.6.3)
xpath (3.2.0) xpath (3.2.0)
nokogiri (~> 1.8) nokogiri (~> 1.8)
@ -467,7 +464,6 @@ DEPENDENCIES
uglifier (>= 1.3.0) uglifier (>= 1.3.0)
validates_hostname validates_hostname
web-console (>= 3.3.0) web-console (>= 3.3.0)
whenever
BUNDLED WITH BUNDLED WITH
1.17.3 1.17.3

View file

@ -79,23 +79,15 @@ class SitesController < ApplicationController
end end
def enqueue def enqueue
@site = find_site site = find_site
authorize @site authorize site
@site.enqueue!
# XXX: Convertir en una máquina de estados?
DeployWorker.perform_async site.id if site.enqueue!
redirect_to sites_path redirect_to sites_path
end end
def build_log
@site = find_site
authorize @site
# TODO: eliminar ANSI
render file: @site.build_log,
layout: false,
content_type: 'text/plain; charset=utf-8'
end
def reorder_posts def reorder_posts
@site = find_site @site = find_site
authorize @site authorize @site

View file

@ -7,8 +7,8 @@ class Site < ApplicationRecord
validates :name, uniqueness: true, hostname: true validates :name, uniqueness: true, hostname: true
validates :design_id, presence: true validates :design_id, presence: true
validate :deploy_local_presence validate :deploy_local_presence
validates_inclusion_of :status, in: %w[waiting enqueued building]
friendly_id :name, use: %i[finders] friendly_id :name, use: %i[finders]
@ -217,65 +217,13 @@ class Site < ApplicationRecord
end.flatten.uniq.compact end.flatten.uniq.compact
end end
def failed_file def enqueue!
File.join(path, '.failed') !enqueued? && update_attribute(:status, 'enqueued')
end
def failed?
File.exist? failed_file
end
def defail
FileUtils.rm failed_file if failed?
end
alias defail! defail
def build_log
File.join(path, 'build.log')
end
def build_log?
File.exist? build_log
end
def queue_file
File.join(path, '.generate')
end end
def enqueued? def enqueued?
File.exist? queue_file status == 'enqueued'
end end
alias queued? enqueued?
# El sitio se genera cuando se coloca en una cola de generación, para
# que luego lo construya un cronjob
def enqueue
defail!
# TODO: ya van tres métodos donde usamos esta idea, convertir en un
# helper o algo
File.open(queue_file, File::RDWR | File::CREAT, 0o640) do |f|
# Bloquear el archivo para que no sea accedido por otro
# proceso u otra editora
f.flock(File::LOCK_EX)
# Empezar por el principio
f.rewind
# Escribir la fecha de creación
f.write(Time.now.to_i.to_s)
# Eliminar el resto
f.flush
f.truncate(f.pos)
end
end
alias enqueue! enqueue
# Eliminar de la cola
def dequeue
FileUtils.rm(queue_file) if enqueued?
end
alias dequeue! dequeue
# Verifica si los posts están ordenados # Verifica si los posts están ordenados
def ordered?(collection = 'posts') def ordered?(collection = 'posts')

View file

@ -55,10 +55,6 @@ class SitePolicy
build? build?
end end
def build_log?
build?
end
def reorder_posts? def reorder_posts?
build? build?
end end

View file

@ -77,15 +77,6 @@
= fa_icon 'building' = fa_icon 'building'
= t('sites.enqueue') = t('sites.enqueue')
- if policy(site).build_log?
- if site.failed?
%button.btn.btn-danger= t('sites.failed')
- if site.build_log?
= render 'layouts/btn_with_tooltip',
tooltip: t('help.sites.build_log'),
text: t('sites.build_log'),
type: 'warning',
link: site_build_log_path(site)
- if policy(site).pull? && site.needs_pull? - if policy(site).pull? && site.needs_pull?
= render 'layouts/btn_with_tooltip', = render 'layouts/btn_with_tooltip',
tooltip: t('help.sites.pull'), tooltip: t('help.sites.pull'),

View file

@ -6,14 +6,20 @@ class DeployWorker
def perform(site) def perform(site)
site = Site.find(site) site = Site.find(site)
site.update_attribute :status, 'building'
# Asegurarse que DeployLocal sea el primero! # Asegurarse que DeployLocal sea el primero!
deployed = { deploy_local: deploy_local(site) } deployed = { deploy_local: deploy_local(site) }
# No es opcional # No es opcional
raise unless deployed[:deploy_local] unless deployed[:deploy_local]
site.update_attribute :status, 'waiting'
raise
end
deploy_others site, deployed deploy_others site, deployed
notify_usuaries site, deployed notify_usuaries site, deployed
site.update_attribute :status, 'waiting'
end end
private private

View file

@ -1,80 +0,0 @@
#!/bin/bash
# TODO convertir a ruby!
set -e
rails_root="${PWD}"
# Encontrar todos los sitios únicos con el archivo `.generate`. Esto
# significa que la usuaria quiso generar el sitio.
find -L ./_sites -mindepth 2 -maxdepth 2 -name .generate \
| sed "s/\/\.generate$//" \
| while read _path ; do
# Como seguimos todos los symlinks y los sitios pueden estar
# vinculados entre sí, volvemos a chequear si existe el archivo para
# no generarlo dos veces
test -f "${_path}/.generate" || continue
test -f "${_path}/.generating" && continue
# Obtenemos las direcciones de correo de las responsables
_mail=($(cat "${_path}/.usuarias"))
_site="$(echo "${_path}" | xargs basename)"
_deploy="${rails_root}/_deploy/${_site}"
# Entrar al directorio del sitio
pushd "${_path}" &>/dev/null
# Reiniciar el log con la fecha
date > build.log
# Instalar las gemas si no están
test -f .bundle/config \
|| bundle install --path=/srv/http/gems.kefir.red \
>> build.log
# Actualizar las gemas
bundle >> build.log
# Instalar los assets
test -f yarn.lock \
&& yarn >> build.log
# Crear el sitio con lujo de detalles y guardar un log, pero a la vez
# tenerlo en la salida estándar para poder enviar al MAILTO del
# cronjob.
#
# Ya que estamos, eliminamos la ruta donde estamos paradas para no dar
# información sobre la servidora.
touch .generating
# Correr en baja prioridad
nice -n 19 \
bundle exec \
jekyll build --trace --destination "${_deploy}" 2>&1 \
| sed -re "s,${_path},,g" \
>> "build.log"
# Acciones posteriores
# TODO convertir en un plugin de cada sitio?
if test $? -eq 0; then
# Si funciona, enviar un mail
# TODO enviar un mail más completo y no hardcodear direcciones
echo "Everything was good! You can see your changes in https://${_site}" \
| mail -b "sysadmin@kefir.red" \
-s "${_site}: :)" \
${_mail[@]}
else
echo "There was an error, please check build log at https://sutty.kefir.red/" \
| mail -b "sysadmin@kefir.red" \
-s "${_site}: :(" \
${_mail[@]}
date +%s >.failed
fi
# Eliminar el archivo para sacar el sitio de la cola de compilación
rm -f .generate .generating
# TODO descubrir el grupo según la distro?
chgrp -R http "${_deploy}"
find "${_deploy}" -type f -print0 | xargs -r -0 chmod 640
find "${_deploy}" -type d -print0 | xargs -r -0 chmod 2750
# Volver al principio para continuar con el siguiente sitio
popd &>/dev/null
done

View file

@ -1,6 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
# rubocop:disable Metrics/BlockLength
Rails.application.routes.draw do Rails.application.routes.draw do
devise_for :usuaries devise_for :usuaries
@ -42,8 +41,6 @@ Rails.application.routes.draw do
# Compilar el sitio # Compilar el sitio
post 'enqueue', to: 'sites#enqueue' post 'enqueue', to: 'sites#enqueue'
get 'build_log', to: 'sites#build_log'
post 'reorder_posts', to: 'sites#reorder_posts' post 'reorder_posts', to: 'sites#reorder_posts'
end end
end end
# rubocop:enable Metrics/BlockLength

View file

@ -1,8 +0,0 @@
# frozen_string_literal: true
env 'MAILTO', 'sysadmin@kefir.red'
job_type :bash, 'cd :path && ./bin/:task'
every 3.minutes do
bash 'jekyll_build_all'
end

View file

@ -1,5 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
# Crea la tabla de estadísticas de compilación
class CreateBuildStats < ActiveRecord::Migration[5.2] class CreateBuildStats < ActiveRecord::Migration[5.2]
def change def change
create_table :build_stats do |t| create_table :build_stats do |t|

View file

@ -0,0 +1,8 @@
# frozen_string_literal: true
# El status de un sitio
class AddStatusToSite < ActiveRecord::Migration[5.2]
def change
add_column :sites, :status, :string, default: 'waiting'
end
end

View file

@ -12,7 +12,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20_190_725_185_427) do ActiveRecord::Schema.define(version: 20_190_726_003_756) do
create_table 'build_stats', force: :cascade do |t| create_table 'build_stats', force: :cascade do |t|
t.datetime 'created_at', null: false t.datetime 'created_at', null: false
t.datetime 'updated_at', null: false t.datetime 'updated_at', null: false
@ -98,6 +98,7 @@ ActiveRecord::Schema.define(version: 20_190_725_185_427) do
t.string 'name' t.string 'name'
t.integer 'design_id' t.integer 'design_id'
t.integer 'licencia_id' t.integer 'licencia_id'
t.string 'status', default: 'waiting'
t.index ['design_id'], name: 'index_sites_on_design_id' t.index ['design_id'], name: 'index_sites_on_design_id'
t.index ['licencia_id'], name: 'index_sites_on_licencia_id' t.index ['licencia_id'], name: 'index_sites_on_licencia_id'
t.index ['name'], name: 'index_sites_on_name', unique: true t.index ['name'], name: 'index_sites_on_name', unique: true

View file

@ -71,4 +71,15 @@ class SitesControllerTest < ActionDispatch::IntegrationTest
} }
end end
end end
test 'se pueden encolar' do
Sidekiq::Testing.fake!
post site_enqueue_url(@site), headers: @authorization
assert DeployWorker.jobs.count.positive?
assert @site.reload.enqueued?
Sidekiq::Testing.inline!
end
end end