Atomicité lors de la création


#1

Bonjour, j’ai 2 modèles qui, au niveau métier sont liés de la manière
suivante :

  • Une classe AR “production” contient entre autre une info de stock
    (dans le
    sens quantité)
  • Une classe AR “mission” puise dans ce stock pour apporter (camion) de
    la
    marchandise vers une autre ville
  • Une mission n’est possible que si le stock correspondant est
    strictement
    positif.

Jusqu’à présent tout se passe dans la classe “mission” :

  • un “validate_on_create” s’assure que le stock est suffisant
  • un “after_create” décrémente le stock de la valeur correspondant à la
    mission

Mon soucis est de rendre ça atomique : lors d’un accès concurrent au
meme
stock, je ne veux pas que 2 personnes pensent qu’il y a du stock, que
les 2
décrémentes, et que finalement le stock devienne négatif vu qu’en fait
il
n’y en avait pas pour les 2.

J’ai bien vu les transactions[1], mais je ne sais pas comment faire pour
la
mettre dans le modèle, vu que ça touche des actions avant et après la
création.

Merci (-:

gUI

[1]
http://api.rubyonrails.com/classes/ActiveRecord/Transactions/ClassMethods.html

Pour la santé de votre ordinateur, préférez les logiciels libres.
Lire son mail : http://www.mozilla-europe.org/fr/products/thunderbird/
Browser le web : http://www.mozilla-europe.org/fr/products/firefox/
Suite bureautique : http://fr.openoffice.org/


#2

2009/2/4 Guillaume B. removed_email_address@domain.invalid:

Jusqu’à présent tout se passe dans la classe “mission” :
mettre dans le modèle, vu que ça touche des actions avant et après la
création.

Je pense que pour être vraiment sur du résultat, tu devrais utiliser
des contraintes sur ta base de données directement.


http://fabien.jakimowicz.com


#3

Sinon, tu peux faire une méthode qui décore create en mettant une
transaction autour, du genre :

class Mission < AR::B

def create_according_to_stock(*args, &block)
self.transaction do
self.create(args, block)
end

end

Et dans ton contrôleur, tu appelles ta méthode décorante à la place du
create normal.

Michel B.

2009/2/4 Fabien J. removed_email_address@domain.invalid


#4

oui, c’est pas mal comme solution.

je vais tenter ça. merci !

gUI

Le 4 février 2009 10:41, Michel B. removed_email_address@domain.invalid
a
écrit :

create normal.

Jusqu’à présent tout se passe dans la classe “mission” :
n’y en avait pas pour les 2.

http://fabien.jakimowicz.com


Pour la santé de votre ordinateur, préférez les logiciels libres.
Lire son mail : http://www.mozilla-europe.org/fr/products/thunderbird/
Browser le web : http://www.mozilla-europe.org/fr/products/firefox/
Suite bureautique : http://fr.openoffice.org/


#5

Peut-être celà serait plus sur avec un lock?

http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html

Car là , avec une transaction, 2 utilisateurs peuvent passer si leur
validation se fait en même temps (la 1ère requête de la transaction
passe et la seconde n’a aucune contrainte pour ne pas passer)


#6

(bon je m’apercois en me relistant que j’ai oublié des indentations et
des
‘end’ mais le principe reste valable)

Michel B.

2009/2/4 Michel B. removed_email_address@domain.invalid


#7

J’avais lu ça, mais apparemment c’est réellement pour les cas extrêmes.
Le
mien est un classique, et s’approche de très près du cas d’école du
transfert d’argent entre 2 comptes.

gUI

Le 4 février 2009 19:45, Tony C. removed_email_address@domain.invalid a
écrit
:


Pour la santé de votre ordinateur, préférez les logiciels libres.
Lire son mail : http://www.mozilla-europe.org/fr/products/thunderbird/
Browser le web : http://www.mozilla-europe.org/fr/products/firefox/
Suite bureautique : http://fr.openoffice.org/


#8

2009/2/4 Guillaume B. removed_email_address@domain.invalid:

J’avais lu ça, mais apparemment c’est réellement pour les cas extrêmes. Le
mien est un classique, et s’approche de très près du cas d’école du
transfert d’argent entre 2 comptes.

C’est un cas qui peut se produire bien plus souvent qu’on ne le pense
: il suffit d’avoir la malchance de 2 utilisateurs qui font au même
moment (proche de la milliseconde) la même action …

Quitte à faire un lock, une contrainte sur la base/table est encore
plus sage : cela ne bloque pas la base de données comme un lock et ca
laisse la base gérer la fiabilité des données.


http://fabien.jakimowicz.com


#9

Fabien J. a écrit :

Quitte à faire un lock, une contrainte sur la base/table est encore
plus sage : cela ne bloque pas la base de données comme un lock et ca
laisse la base gérer la fiabilité des données.
Sauf que la philosophie de rails est de ne rien faire en DB et de tout
gérer dans le modèle ou via l’ORM, dans l’application.
Je ne suis pas trop d’accord avec cette idée, et préfèrerais un moyen
d’implémenter des contraintes (FK, …) au niveau de la DB si celle ci
la gère, mais cela n’est pas du tout prévu (un choix de conception de
DHH, qui a été discuté).

renchap


#10

2009/2/4 Renaud C. removed_email_address@domain.invalid:

DHH, qui a été discuté).

en effet, mais les index uniques (qui sont implémentés dans rails)
contredisent totalement cette logique rails.

De plus, tout n’est pas possible depuis les modèles :wink:


http://fabien.jakimowicz.com


#11

Renaud C. wrote:

Fabien J. a écrit :

Quitte à faire un lock, une contrainte sur la base/table est encore
plus sage : cela ne bloque pas la base de données comme un lock et ca
laisse la base gérer la fiabilité des données.
Sauf que la philosophie de rails est de ne rien faire en DB et de tout
gérer dans le modèle ou via l’ORM, dans l’application.
Je ne suis pas trop d’accord avec cette idée, et préfèrerais un moyen
d’implémenter des contraintes (FK, …) au niveau de la DB si celle ci
la gère, mais cela n’est pas du tout prévu (un choix de conception de
DHH, qui a été discuté).

renchap

C’est un choix qui se comprend si l’on souhaite réellement ne pas
dépendre de la base de donnée choisie. Mais celà ne doit pas non plus
empêcher toute optimisation dans le cas d’un projet où le choix de la
base est connu et pérenne


#12

Je sais, c’est pour ça que je m’en inquiète, mais la transaction Rails
sert
à ça non ?

C’est pas exactement le même problème. La transaction permet d’enchainer
plusieurs requêtes en annulant tout si l’une d’entre elles échoue.
Le lock interdit l’accès en écriture à une table (ou juste une ligne de
cette table) tant qu’on a pas rendu la main.


#13

C’est pas exactement le même problème. La transaction permet d’enchainer
plusieurs requêtes en annulant tout si l’une d’entre elles échoue.
Le lock interdit l’accès en écriture à une table (ou juste une ligne de
cette table) tant qu’on a pas rendu la main.

Ah bin j’avais rien compris (-:

Donc oui en effet j’ai bien besoin d’un lock.

gUI


Pour la santé de votre ordinateur, préférez les logiciels libres.
Lire son mail : http://www.mozilla-europe.org/fr/products/thunderbird/
Browser le web : http://www.mozilla-europe.org/fr/products/firefox/
Suite bureautique : http://fr.openoffice.org/


#14

C’est un cas qui peut se produire bien plus souvent qu’on ne le pense
: il suffit d’avoir la malchance de 2 utilisateurs qui font au même
moment (proche de la milliseconde) la même action …

Je sais, c’est pour ça que je m’en inquiète, mais la transaction Rails
sert
à ça non ?

gUI


Pour la santé de votre ordinateur, préférez les logiciels libres.
Lire son mail : http://www.mozilla-europe.org/fr/products/thunderbird/
Browser le web : http://www.mozilla-europe.org/fr/products/firefox/
Suite bureautique : http://fr.openoffice.org/


#15

En fait, à ta place je ferais les deux approches à la fois. Le blocage
de
l’objet t’assure la non-concurrence des requêtes (le script est le seul
Ã
passer à la fois), et la transaction t’assure l’atomicité (tout passe Ã
la
fois ou rien ne passe du tout).
Michel B.

2009/2/4 Tony C. removed_email_address@domain.invalid


#16

Disons, dans ce cas-là c’est un peu toi qui assure l’atomicité en
vérifiant
que le compte y est et que tu ne décrémente que si le nouvel objet est
validé. Si tu ne faisais pas ça, le lock ne serait pas suffisant.

Michel B.

2009/2/5 Guillaume B. removed_email_address@domain.invalid


#17

Je peux toujours essayer, ne serait-ce que pour l’exercice.

Mais cela dit, je me suis trompé. En y réfléchissant bien, si j’ai la
non
concurrence, j’ai pas besoin de l’atomicité.

Et au passage j’ajouterais que il me semble que “atomicité” est ici
impropre
: l’atomicité garantissant normalement la non-concurrence (en tous cas
dans
le cadre des instructions processeur), puisque dans opération atomique
on
parle de operation non interruptible.

gUI

Le 5 février 2009 07:26, Michel B. removed_email_address@domain.invalid
a
écrit :


Posted via http://www.ruby-forum.com/.


Pour la santé de votre ordinateur, préférez les logiciels libres.
Lire son mail : http://www.mozilla-europe.org/fr/products/thunderbird/
Browser le web : http://www.mozilla-europe.org/fr/products/firefox/
Suite bureautique : http://fr.openoffice.org/