Skip to content
Snippets Groups Projects
Select Git revision
  • 6aff4e917e5f14ab5e465251de369bc0b50467c4
  • devel default
  • master
  • fo
  • jirka/typing
  • fo-base
  • mj/submit-images
  • jk/issue-96
  • jk/issue-196
  • honza/add-contestant
  • honza/mr7
  • honza/mrf
  • honza/mrd
  • honza/mra
  • honza/mr6
  • honza/submit-images
  • honza/kolo-vs-soutez
  • jh-stress-test-wip
  • shorten-schools
19 results

mo-submit

Martin Mares's avatar
Martin Mareš authored
Closes #314:

Pokud organizátor odešle POST na přidání nového účastníka soutěže
dvakrát rychle po sobě (třeba kvůli nějakému automatickému retry
po rozpadu spojení), dvě různé DB transakce se snaží založit uživatele
se stejným loginem. Jedna z nich selže na unikátnosti sloupce email.

V defaultní úrovni izolace transakcí (READ COMMITTED) to nemá žádné
hezké řešení. Nepomůže SELECT ... FOR UPDATE, jelikož ten zamyká pouze
nalezené řádky, nikoliv neexistenci dalších řádků vyhovujících podmínce.

Co by se dalo dělat:

(1) Zvýšit úroveň izolace aspoň na READ REPEATABLE. To vyřeší problém,
    ale současně může začít víceméně jakákoliv zapisující transakce
    failovat. Vyžadovalo by dopsat retry do prakticky všech míst v OSMO,
    kde je nějaký commit.

(2) Retryovat specificky transakce na zakládání užívatelů (a účastí apod.).
    Tohle nejde snadno, jelikoz jsou i součástí dlouho běžících transakcí
    v importech (zatím jsme se snažíli, aby byl celý import atomický
    a v případě selhání se celý rollbackoval). To by možná mohly vyřešit
    subtransakce.

(3) Zamykat celou tabulku s uživateli, než na ní provedeme první SELECT.
    To by asi vyřešilo problém, ale byl by potřeba zápisový zámek, takže
    by paralelně nemohla běžet žádná čtení. A také by se to potenciálně
    mohlo deadlockovat (potřebujeme v jedné transakci postupně lock na
    uživatele, účastníky a účasti a locky platí až do konce transakce).

(4) Používat INSERT ... ON CONFLICT <něco>. To vypadá bezpečně, jen to není
    moc pohodlné, zejména proto, že s tím nepočítá ORM, takže je potřeba
    dělat všechno ručně.

Zatím jsem zvolil (4), protože mi přijde, že to změny udržuje lokální
a funguje i s dlouhými transakcemi při importu. Výhledově bych se ale
chtěl zamyslet nad tím, jak takové věci řešit co nejuniverzálněji
a nejpohodlněji.
6aff4e91
History

Odevzdávací Systém Matematické Olympiády

OSMO je webová aplikace pro účastníky i organizátory Matematické olympiády, která obstarává většinu agendy okolo chodu soutěže: přihlášky, zadávání úloh, odevzdávání řešení, bodování, sestavování výsledkových listin atd.

OSMO primárně vzniklo pro českou Matematickou olympiádu, ale po menších úpravách ho lze používat i pro jiné, podobné soutěže. Není v našich silách provozovat další instance OSMO, ale pokud chcete s úpravami a provozem systému poradit, ozvěte se nám na adrese osmo@mo.mff.cuni.cz.

OSMO můžete používat a distribuovat pod licencí GNU Affero General Public License verze 3 nebo novější (viz soubor LICENSE).

Autoři

Martin Mareš <mj@ucw.cz>
Jiří Kalvoda
Jan Prachař
Jiří Setnička

Instalace vývojového prostředí

python3 -m venv venv
. venv/bin/activate
pip install wheel
pip install -c constraints.txt --editable .
# vytvořit mo/config.py podle etc/config.py.example
bin/init-data-dir

bin/flask run

# Po běžných úpravách není potřeba balíček přeinstalovávat

Instalace na produkční server

# Pro systém s jádrem < 5.4 zvýšit net.core.somaxconn (jako root)
[ "`cat /proc/sys/net/core/somaxconn`" -lt 4096 ] && echo net.core.somaxconn=4096 >> /etc/sysctl.conf && sysctl -p

# Založit účet mo-web (jako root)
adduser --system mo-web --shell /bin/bash
loginctl enable-linger mo-web

# Založit databázi (jako správce PostgreSQL)
psql -c 'CREATE ROLE mo_osmo'
psql -c 'CREATE ROLE "mo-web" LOGIN'
psql -c 'GRANT mo_osmo TO "mo-web"'	# a případně dalším uživatelům
psql -c 'CREATE DATABASE mo_osmo_test WITH OWNER=mo_osmo'

# Inicializovat databázi (už jako mo-web)
psql mo_osmo_test <db/db.ddl

# Založit adresář pro instanci
mkdir /akce/mo/osmo-test
chmod 770 /akce/mo/osmo-test
setfacl -m u:mo-web:rwx -m g:mo:rwx /akce/mo/osmo-test
setfacl -d -m u:mo-web:rwx -m g:mo:rwx /akce/mo/osmo-test

# Zbytek jako uživatel mo-web v /akce/mo/osmo-test
git clone <repozitář> src

# Vytvořit etc/config.py podle src/etc/config.py.example
# Vytvořit etc/uwsgi.ini podle src/etc/uwsgi.ini.example
cd src
bin/deploy

# Zpřístupnit socket Nginxu
setfacl -m u:www-data:x /akce/mo/osmo-test /akce/mo/osmo-test/var

# Inicializovat regiony v DB
# Obstarat si extra/ruian/ a extra/schools/parsed/ z jiné instance (nebo je znovu stáhnout)
. ../venv/bin/activate
bin/test-init mo_osmo_test data		# případně podmnožinu

# Případně ručně otestovat, že uwsgi funguje
# uwsgi --ini etc/osmo.ini

# Založit ~/.config/systemd/user/osmo_test.service podle etc/osmo.service.example
systemctl --user daemon-reload
systemctl --user enable osmo_test.service
systemctl --user start osmo_test.service
systemctl --user status osmo_test.service

# Nastavit nginx:
location /osmo-test {
	include uwsgi_params;
	uwsgi_pass unix:/akce/mo/osmo-test/var/osmo.sock;
}

# Na instalaci nové verze pak stačí spustit bin/deploy

Mražení závislostí

pip freeze | grep -v '^osmo=' >constraints.txt

Testovací prostředí

# Umíme automaticky založit testovací prostředí se soutěžemi, uživateli
# a jejich rolemi. Obvykle na to používáme samostatnou databázi a datový
# adresář.

# Do mo/config.py připsat:
SQLALCHEMY_DATABASE_URI = ... připojení k databázi mo_osmo_test
DATA_DIR = "data-test"
CURRENT_YEAR = 42
INSECURE_TEST_LOGIN = True

# Vytvoření prostředí
bin/test-init mo_osmo_test data-test

# Spuštění webových prohlížečů pro testovací uživatele
bin/test-browser garanti

# Přepnutí soutěží do konkrétního stavu
bin/test-state running