Compare commits

...

7 Commits
faaso ... main

Author SHA1 Message Date
e01d2292da Cambio a rocky 2024-09-04 09:50:11 -03:00
5449518566 Cambio a rocky 2024-09-03 15:20:30 -03:00
eb9db947bd Cambio a rocky 2024-09-03 12:17:02 -03:00
9190060c52 Don't use pg pool, too flaky for now 2024-08-21 18:18:35 -03:00
dbbf7224b3 foo 2024-08-21 17:55:43 -03:00
1e5f913c70 Portado tapas 2024-08-21 17:54:09 -03:00
d57a58b45a placeholder 2024-08-21 16:52:00 -03:00
10 changed files with 104 additions and 82 deletions

View File

@ -1,5 +1,6 @@
require "json" require "json"
require "kemal" require "kemal"
require "db"
require "pg" require "pg"
require "pool/connection" require "pool/connection"
@ -11,11 +12,6 @@ DBHOST = File.read("/secrets/dbhost").strip
DBURL = "postgres://#{USER}:#{PASS}@#{DBHOST}:5432/nombres" DBURL = "postgres://#{USER}:#{PASS}@#{DBHOST}:5432/nombres"
puts "Connnecting to #{DBURL}" puts "Connnecting to #{DBURL}"
# Create a connection pool to the database
pg = ConnectionPool.new(capacity: 5, timeout: 1.seconds) do
PG.connect(DBURL)
end
def normalize(s : String) : String def normalize(s : String) : String
s.unicode_normalize(:nfkd) s.unicode_normalize(:nfkd)
.chars.reject! { |character| .chars.reject! { |character|
@ -25,6 +21,7 @@ end
# A basic hello world get endpoint # A basic hello world get endpoint
post "/" do |env| post "/" do |env|
db = DB.open DBURL
prefijo = env.params.json["p"].as(String) prefijo = env.params.json["p"].as(String)
genero = env.params.json["g"].as(String) genero = env.params.json["g"].as(String)
year = env.params.json["a"].as(String) year = env.params.json["a"].as(String)
@ -35,34 +32,33 @@ post "/" do |env|
end end
datos = [] of Tuple(String, Int32 | String) datos = [] of Tuple(String, Int32 | String)
# Connect using credentials provided # Connect using credentials provided
pg.connection do |cursor| if prefijo.empty? && year.empty?
if prefijo.empty? && year.empty? result_set = db.query("
result_set = cursor.query("
SELECT nombre, total::integer SELECT nombre, total::integer
FROM totales FROM totales
ORDER BY total DESC ORDER BY total DESC
LIMIT 50") LIMIT 50")
elsif prefijo.empty? && !year.empty? elsif prefijo.empty? && !year.empty?
# Per-year totals # Per-year totals
result_set = cursor.query(" result_set = db.query("
SELECT nombre, contador::integer SELECT nombre, contador::integer
FROM nombres FROM nombres
WHERE WHERE
anio = $1 anio = $1
ORDER BY contador DESC ORDER BY contador DESC
LIMIT 50", year) LIMIT 50", year)
elsif !prefijo.empty? && year.empty? elsif !prefijo.empty? && year.empty?
# Filter only by prefix # Filter only by prefix
result_set = cursor.query(" result_set = db.query("
SELECT nombre, total::integer SELECT nombre, total::integer
FROM totales FROM totales
WHERE WHERE
nombre LIKE $1 nombre LIKE $1
ORDER BY total DESC ORDER BY total DESC
LIMIT 50", prefijo + "%") LIMIT 50", prefijo + "%")
elsif !prefijo.empty? && !year.empty? elsif !prefijo.empty? && !year.empty?
# We have both # We have both
result_set = cursor.query(" result_set = db.query("
SELECT nombre, contador::integer SELECT nombre, contador::integer
FROM nombres FROM nombres
WHERE WHERE
@ -70,20 +66,19 @@ post "/" do |env|
nombre LIKE $2 nombre LIKE $2
ORDER BY contador DESC ORDER BY contador DESC
LIMIT 50", year, prefijo + "%") LIMIT 50", year, prefijo + "%")
end end
if !result_set.nil? if !result_set.nil?
result_set.each do result_set.each do
nombre = result_set.read(String) nombre = result_set.read(String)
valor = result_set.read(Int32) valor = result_set.read(Int32)
datos.push({nombre, valor}) datos.push({nombre, valor})
end
result_set.close
end end
result_set.close
end
if datos.empty? if datos.empty?
raise "No data found" raise "No data found"
end
end end
# In this context, remove all composite names # In this context, remove all composite names
datos.reject! { |row| datos.reject! { |row|
@ -92,39 +87,37 @@ post "/" do |env|
datos.insert(0, {"Nombre", "Cuantos?"}) datos.insert(0, {"Nombre", "Cuantos?"})
if genero if genero
pg.connection do |cursor| datos.reject! { |row|
datos.reject! { |row| # How feminine is this name?
# How feminine is this name? # Yes this database is upper case
# Yes this database is upper case puts "Checking #{row[1]} #{row[0]}"
puts "Checking #{row[1]} #{row[0]}" feminidad = 0
feminidad = 0 sql = %(
sql = %(
SELECT COALESCE((SELECT frecuencia FROM mujeres WHERE nombre='#{row[0]?.to_s.upcase}'), 0) AS mujeres, SELECT COALESCE((SELECT frecuencia FROM mujeres WHERE nombre='#{row[0]?.to_s.upcase}'), 0) AS mujeres,
COALESCE((SELECT frecuencia FROM hombres WHERE nombre='#{row[0]?.to_s.upcase}'), 0) AS hombres COALESCE((SELECT frecuencia FROM hombres WHERE nombre='#{row[0]?.to_s.upcase}'), 0) AS hombres
) )
puts "SQL: #{sql}" puts "SQL: #{sql}"
cursor.query sql do |result_set| db.query sql do |result_set|
result_set.each do result_set.each do
mujeres = result_set.read(Int32) mujeres = result_set.read(Int32)
hombres = result_set.read(Int32) hombres = result_set.read(Int32)
puts "frecuencias: #{mujeres} #{hombres}" puts "frecuencias: #{mujeres} #{hombres}"
if hombres == mujeres == 0 if hombres == mujeres == 0
feminidad = 0.5 feminidad = 0.5
else else
feminidad = mujeres / (hombres + mujeres) feminidad = mujeres / (hombres + mujeres)
end
end end
end end
# El overlap en 0.5 es intencional! end
if (feminidad >= 0.5 && genero == "f") || # El overlap en 0.5 es intencional!
(feminidad <= 0.5 && genero == "m") if (feminidad >= 0.5 && genero == "f") ||
false (feminidad <= 0.5 && genero == "m")
else false
true else
end true
} end
puts "Data split by gender" }
end puts "Data split by gender"
end end
datos = datos[..10].map { |row| datos = datos[..10].map { |row|
[row[0].capitalize, row[1]] [row[0].capitalize, row[1]]
@ -141,9 +134,14 @@ post "/" do |env|
"title" => title, "title" => title,
"data" => datos, "data" => datos,
}.to_json }.to_json
ensure
db.try &.close
end end
get "/ping/" do get "/ping/" do
pg.connection.exec("SELECT 42") db = DB.open DBURL
db.exec("SELECT 42")
"OK" "OK"
ensure
db.try &.close
end end

View File

@ -1,6 +1,6 @@
#!/bin/sh -x #!/bin/sh -x
set -e set -e
#export OPENFAAS_URL=http://pinky:8082 export OPENFAAS_URL=http://pinky:8082
#pass faas.ralsina.me | faas-cli login -u admin --password-stdin #pass faas.ralsina.me | faas-cli login -u admin --password-stdin
#pass iol-pass | faas-cli secret create iol-pass #pass iol-pass | faas-cli secret create iol-pass
@ -14,15 +14,18 @@ export FAASO_SERVER=http://rocky:8888/admin
pass faaso-rocky | faaso login pass faaso-rocky | faaso login
pass nombres-user | faaso secret -a historico user pass nombres-user | faaso secret -a historico user
pass nombres-pass | faaso secret -a historico pass pass nombres-pass | faaso secret -a historico pass
echo "192.168.0.98" | faaso secret -a historico dbhost echo "rocky.tail20c16.ts.net" | faaso secret -a historico dbhost
faaso build busqueda faaso build busqueda
faaso scale busqueda 0 faaso scale busqueda 0
faaso scale busqueda 1 faaso scale busqueda 1
pass nombres-user | faaso secret -a busqueda user pass nombres-user | faaso secret -a busqueda user
pass nombres-pass | faaso secret -a busqueda pass pass nombres-pass | faaso secret -a busqueda pass
echo "192.168.0.98" | faaso secret -a busqueda dbhost echo "rocky.tail20c16.ts.net" | faaso secret -a busqueda dbhost
faaso build historico faaso build historico
faaso scale historico 0 faaso scale historico 0
faaso scale historico 1 faaso scale historico 1
rsync -rav nombres.ralsina.me/* ralsina@rocky:/data/stacks/web/websites/nombres.ralsina.me/
rsync -rav nombres.ralsina.me/* ralsina@pinky:/data/websites/nombres.ralsina.me/ faaso build tapas
faaso scale tapas 0
faaso scale tapas 1

View File

@ -3,10 +3,6 @@ provider:
name: openfaas name: openfaas
gateway: http://pinky:8082 gateway: http://pinky:8082
functions: functions:
tapas:
lang: python3-flask
handler: ./tapas
image: ralsina/tapas:latest
iol: iol:
lang: python3-fastapi lang: python3-fastapi
handler: ./iol handler: ./iol

View File

@ -11,11 +11,6 @@ DBHOST = File.read("/secrets/dbhost").strip
DBURL = "postgres://#{USER}:#{PASS}@#{DBHOST}:5432/nombres" DBURL = "postgres://#{USER}:#{PASS}@#{DBHOST}:5432/nombres"
puts "Connnecting to #{DBURL}" puts "Connnecting to #{DBURL}"
# Create a connection pool to the database
pg = ConnectionPool.new(capacity: 5, timeout: 1.seconds) do
PG.connect(DBURL)
end
# Connect to the database and get information about # Connect to the database and get information about
# the requested names # the requested names
get "/" do |env| get "/" do |env|
@ -31,7 +26,7 @@ get "/" do |env|
results << [anio.to_s] results << [anio.to_s]
end end
# Connect using credentials provided # Connect using credentials provided
pg.connection do |cursor| db = DB.open DBURL
# Get the information for each name # Get the information for each name
names.map do |name| names.map do |name|
# Normalize: remove diacritics etc. # Normalize: remove diacritics etc.
@ -41,7 +36,7 @@ get "/" do |env|
}.join("").downcase }.join("").downcase
counter_per_year = {} of Int32 => Int32 counter_per_year = {} of Int32 => Int32
cursor.query(" db.query("
SELECT anio::integer, contador::integer SELECT anio::integer, contador::integer
FROM nombres WHERE nombre = $1", name) do |result_set| FROM nombres WHERE nombre = $1", name) do |result_set|
result_set.each do result_set.each do
@ -52,15 +47,15 @@ get "/" do |env|
results[anio - 1921] << counter_per_year.fetch(anio, 0).to_s results[anio - 1921] << counter_per_year.fetch(anio, 0).to_s
end end
end end
end
results.to_json results.to_json
ensure
db.try &.close
end end
# The `/ping/` endpoint is configured in the container as a healthcheck
# You can make it better by checking that your database is responding
# or whatever checks you think are important
#
get "/ping/" do get "/ping/" do
pg.connection.exec("SELECT 42") db = DB.open DBURL
db.exec("SELECT 42")
"OK" "OK"
ensure
db.try &.close
end end

View File

@ -306,6 +306,7 @@
id="nombres" id="nombres"
placeholder="Nombres separados con comas" placeholder="Nombres separados con comas"
aria-label="Search" aria-label="Search"
value="juan,maria"
/> />
<input type="submit" value="Buscar" onCLick="drawChart2();" /> <input type="submit" value="Buscar" onCLick="drawChart2();" />
</form> </form>

View File

@ -1,10 +1,12 @@
from json import loads from flask import Flask, request
from tapita import Cover from tapita import Cover
from io import BytesIO from io import BytesIO
import base64 import base64
app = Flask("tapas")
def handle(req): @app.route('/', methods=['POST'])
def handle():
"""handle a request to the function """handle a request to the function
Args: Args:
req (str): request body req (str): request body
@ -15,10 +17,10 @@ def handle(req):
"author": "bat", "author": "bat",
} }
""" """
if not req: if not request:
return "Foo", 200, {"Content-Type": "text/plain"} return "Foo", 200, {"Content-Type": "text/plain"}
try: try:
args = loads(req) args = request.json
except Exception: except Exception:
return "Bad Request", 400 return "Bad Request", 400
@ -31,3 +33,9 @@ def handle(req):
200, 200,
{"Content-Type": "text/html"}, {"Content-Type": "text/html"},
) )
@app.route('/ping')
def ping():
return "OK"

18
tapas/funko.yml Normal file
View File

@ -0,0 +1,18 @@
name: tapas
runtime: flask
options:
ship_packages:
- jpeg
- zlib
- freetype
devel_packages:
- zlib-dev
- jpeg-dev
- freetype-dev
healthcheck_options: "--interval=1m --timeout=2s --start-period=2s --retries=3"
healthcheck_command: "curl --fail http://localhost:3000/ping || exit 1"
copy_from_build:
- "static static"
- "venv venv"
- "run.sh ."
- "funko.py ."

View File

@ -1 +1,2 @@
flask
tapita tapita

2
tapas/run.sh Normal file
View File

@ -0,0 +1,2 @@
#!/bin/sh
uwsgi --plugins http,python -H venv --http 0.0.0.0:3000 --master -p 1 -w funko:app