[C#] Invoer volgorde aanhouden in de database

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Jitse H
  • Registratie: Mei 2011
  • Laatst online: 19:54
Ik heb een programma die berichten maakt, deze berichten wil ik graag in een MySQL server stoppen, zodat ik deze berichten met PHP kan verwerken.

De software staat alleen toe om doormiddel van commandline de gegevens door te sturen.
Ik heb hiervoor een C# applicatie gemaakt (Post.exe) die de berichten in de MySQL database zet.
Dit ziet er als volgt uit:

Afbeeldingslocatie: http://www.jitsehijlkema.nl/tweakers/schematisch.jpg

Het probleem waar ik nu tegen aan loop is dat de berichten elkaar erg snel volgen.
Dit heeft tot gevolg dat er daardoor meerdere processen van Post.exe lopen waarvan de ene soms net iets sneller klaar is dan de ander. Hierdoor komen de berichten soms in de verkeerde volgorde in de database. Hierdoor zien de berichten elkaar niet tijdens het invoegen en kunen dus de berichten niet met elkaar gekoppeld worden.

Volgens mij zal ik het Post.exe programma aan moeten passen zodat deze de invoer eerst cached en vervolgens per bericht het gaat toevoegen aan de database. Op deze manier zou de volgordekoppeling goed blijven.

Het Post.exe programma is nu vrij simpel, doormiddel van een HttpWebRequest wordt het naar een .php bestand gestuurd op de webserver waar de database staat. Deze plaatst het vervolgens in de database.
Ik weet dat ik ook op de webserver het kan cachen in een bestand en deze dan met een cronjob kan laten invoeren, maar dan zit je met een vertraging van 1 minuut ( omdat cronjobs niet sneller achterelkaar kunnen lopen ).

Ik denk dat ik het Post.exe programma moet aanpassen, dat deze als service draait waar dan het programma tegen praat. Dit zorgt er dan voor dat het programma Post.exe niet meerdere keren kan opstarten en dat zou volgens mij mijn probleem op kunnen lossen...

Ik heb geen idee hoe ik hierop moet zoeken op internet, de zoekresultaten totdusver hebben vrijwel niets opgeleverd. Wie wil mij een zetje in de goede richting geven?

Alvast bedankt!

[ Voor 4% gewijzigd door Jitse H op 06-02-2012 20:06 . Reden: Probleem niet goed beschreven ]


Acties:
  • 0 Henk 'm!

  • Kwastie
  • Registratie: April 2005
  • Laatst online: 17-09 13:58

Kwastie

Awesomeness

Kun je niet gewoon "de tijd" meesturen waarop het bericht gepost is? (de "Post.exe" stuurt dus ook een tijd naar de server toe)

[ Voor 30% gewijzigd door Kwastie op 05-02-2012 21:52 ]

When I get sad i stop being sad and be awesome instead


Acties:
  • 0 Henk 'm!

  • Jitse H
  • Registratie: Mei 2011
  • Laatst online: 19:54
Kwastie schreef op zondag 05 februari 2012 @ 21:52:
Kun je niet gewoon "de tijd" meesturen waarop het bericht gepost is? (de "Post.exe" stuurt dus ook een tijd naar de server toe)
Helaas niet, die tijd is zelfs ook op de seconde gelijk. En de processen kunnen nu parallel lopen zodat het dan nog steeds verkeerd kan gaan...

[ Voor 80% gewijzigd door Jitse H op 05-02-2012 21:56 ]


Acties:
  • 0 Henk 'm!

  • kaesve
  • Registratie: Maart 2009
  • Laatst online: 16-05 03:04
als ze niet op 't zelfde moment binnen komen, is de tijd waarop ze binnenkomen anders (al scheelt het maar 1 tick) en kun je een verschillende tijd meesturen. als ze tegelijk binnenkomen, kun je ook niet onderscheiden welke eerst moet en is een gelijke tijd dus ook niet erg. dus wat is precies het probleem met een tijd meesturen?

Acties:
  • 0 Henk 'm!

  • Kwastie
  • Registratie: April 2005
  • Laatst online: 17-09 13:58

Kwastie

Awesomeness

Jitse H schreef op zondag 05 februari 2012 @ 21:52:
[...]


Helaas niet, die tijd is zelfs ook op de seconde gelijk.
C#:
1
DateTime.Now.ToString("HH:mm:ss.ffffff");


Dit geeft je tijd met microseconden, kan met niet voorstellen dat ze tegelijk lopen.. :9

[ Voor 8% gewijzigd door Kwastie op 05-02-2012 21:57 ]

When I get sad i stop being sad and be awesome instead


Acties:
  • 0 Henk 'm!

  • Jitse H
  • Registratie: Mei 2011
  • Laatst online: 19:54
Bedankt voor het meedenken. Helaas is het toevoegen van microseconden niet de oplossing;

De meldingen zijn bijvoorbeeld

10:15:01 tekst melding 1 voor YYY | A
10:15:01 tekst melding 2 voor YYY | A
10:15:04 tekst melding 3 voor XXX | B 10:15:04 tekst melding 4 voor XXX | B
10:15:04 tekst melding 5 voor XXX | B

Het is de bedoeling dat deze meldingen gekoppeld worden met elkaar. Hiervoor wordt in het voorbeeld de letter A & B gebruikt.
Nu komt het voor dat er 2 meldingen tegelijkertijd bij de database aan komen en dat ze elkaar niet zien, dit zorgt ervoor dat er 2 losse koppelingen zijn. Nu draait er dus een cronjob die dit achteraf weer hersteld, maar hier wil ik dus van af. Vandaar dat ik denk dat ik dit moet zoeken in een oplossing van een service, omdat ze dan niet tegelijkertijd meer aan kunnen komen, ze moeten dan even op elkaar wachten.

[ Voor 5% gewijzigd door Jitse H op 05-02-2012 22:04 ]


Acties:
  • 0 Henk 'm!

  • YakuzA
  • Registratie: Maart 2001
  • Niet online

YakuzA

Wat denk je nou zelluf hey :X

je zou van wat je post.exe nu doet wel een service kunnen maken waar je met locking kan voorkomen dat er 2 tegelijk ingevoerd worden.
Standaard garandeerd locking nog geen order, dus daar zal je nog iets voor moeten verzinnen in dat geval

Death smiles at us all, all a man can do is smile back.
PSN


Acties:
  • 0 Henk 'm!

  • Jitse H
  • Registratie: Mei 2011
  • Laatst online: 19:54
Zolang de berichten elkaar maar kunnen zien, wat nu dus niet altijd het geval is.
Zou je kunnen aangeven waar ik op moet zoeken "je zou van wat je post.exe nu doet wel een service kunnen maken waar je met locking kan voorkomen dat er 2 tegelijk ingevoerd worden." Heb gezocht op C# en service maar daar kom ik niet echt verder mee. Ik werk regelmatig met PHP maar C# is erg nieuw voor mij. Ik was al blij dat ik dit simpele programmaatje had geschreven :P

Acties:
  • 0 Henk 'm!

  • ZaZ
  • Registratie: Oktober 2002
  • Laatst online: 19-08 14:24

ZaZ

Tweakers abonnee

Ik zie het voordeel van een service eigenlijk niet.
Waarom trouwens niet het hele zwikkie guarden met een mutex?

edit:
werkt overigens alleen als post.exe maar vanaf 1 computer draait

[ Voor 26% gewijzigd door ZaZ op 06-02-2012 09:06 ]

Lekker op de bank


Acties:
  • 0 Henk 'm!

  • xPhantom
  • Registratie: December 2008
  • Niet online
Misschien iets geks, maar een auto increment ID door de MySQL server laten toevoegen per bericht?

Acties:
  • 0 Henk 'm!

  • Haan
  • Registratie: Februari 2004
  • Laatst online: 20:53

Haan

dotnetter

Je zou hiervoor eigenlijk denk ik het best een MessageQueue kunnen pakken.
Maar is wellicht wat complex als je nog niet zo bedreven bent met .NET (mijn eigen ervaring is al een paar jaar geleden, misschien dat het intussen makkelijker is geworden)

[ Voor 35% gewijzigd door Haan op 06-02-2012 08:44 ]

Kater? Eerst water, de rest komt later


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Gaat natuurlijk allemaal niets helpen, meer informatie dan Process.GetCurrentProcess().StartTime.ToString("HH:mm:ss.fffffff") is er simpelweg niet meer aangezien handles hergebruikt worden. Dat zou wel net iets beter moeten werken dan gewoon de huidige tijd opvragen, en je zou kunnen denken dat Process.GetCurrentProcess().Id als 2e-orde criterium kan dienen en hopen dat die handle niet hergebruikt is. :p

Edit: even getest, denk dat Process.GetCurrentProcess().StartTime.Ticks toch wel nauwkeurig genoeg zal zijn aangezien het opstarten van een process meestal wel een tick kost en de volledige precessie beschikbaar is.

[ Voor 21% gewijzigd door pedorus op 06-02-2012 10:24 ]

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 16-09 09:15

Janoz

Moderator Devschuur®

!litemod

TS praat over het in de verkeerde volgorde aankomen van de berichten, maar als ik Jitse H in "\[C#] Invoer volgorde aanhouden in de database" lees dan denk ik dat hij eigenlijk een heel ander probleem bedoeld.

Het is niet de volgorde, maar een raceprobleem. Twee berichten die tegelijk komen zien elkaar nog niet in de database waardoor ze niet gekoppeld kunnen worden. De plek waar dit opgelost moet worden is niet in de post.exe, maar op de server. Eerste wat bij mij opkomt is inderdaad een queue gebruiken, maar aangezien je op de server met php werkt heb je die niet tot je beschikking. Wat je ook kunt doen is je model iets verder normalizeren. de 'a' en 'b' neem je op in een aparte tabel met daarop een unique constraint. Bij het inserten krijgt 1 van beiden dan vanzelf een unique constraint violation en kan vervolgens alsnog de berichten koppelen.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Aha. Als er maar 1 client is dan kun je ook simpelweg een mutexje om de webrequest gooien zodat er altijd maar 1 request tegelijkertijd is.

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 16-09 09:15

Janoz

Moderator Devschuur®

!litemod

Op zich is er maar 1 client, maar voor zover ik zie worden die post executables opgestart door externe invloeden waardoor er gewoon per bericht 1 executable draait (en er dus meerdere instanties van die post.exe draaien). Geen idee of het doenbaar is om een mutex te hebben die voor meerdere processen geldt.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Janoz schreef op maandag 06 februari 2012 @ 11:24:
Geen idee of het doenbaar is om een mutex te hebben die voor meerdere processen geldt.
Geen probleem, daar zijn ze voor, lees anders even het stukje over named mutexes. Wel handig om een unieke naam te kiezen, bijvoorbeeld een GUID (makkelijk te maken onder Tools-menu). ;)

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
pedorus schreef op maandag 06 februari 2012 @ 12:12:
bijvoorbeeld een GUID (makkelijk te maken onder Tools-menu). ;)
Of met Guid.NewGuid() :Y)

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Ehh, het moet wel uniek zijn maar verder wel steeds hetzelfde. Dus die functie niet aanroepen in post.exe ;)

[ Voor 5% gewijzigd door pedorus op 06-02-2012 12:52 ]

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
pedorus schreef op maandag 06 februari 2012 @ 12:51:
Ehh, het moet wel uniek zijn maar verder wel steeds hetzelfde. Dus die functie niet aanroepen in post.exe ;)
Uiteraard. Ik rag dat alleen in 't immediate window i.p.v. een omslachtig menu :Y) Moet ik weer muizen :P
Afbeeldingslocatie: http://tweakers.net/ext/f/gPnr8VWQ3b3mx0yrMBjPm7hS/full.png

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
Maar vertel nu eens waarom je niet gewoon DateTime.Now mee kunt inserten als het 'probleem' is dat er meerdere processen tegelijkertijd gestart worden? Kan me niet voorstellen dat dat in dezelfde milliseconde gebeurt.

https://niels.nu


Acties:
  • 0 Henk 'm!

  • BikkelZ
  • Registratie: Januari 2000
  • Laatst online: 21-02 08:50

BikkelZ

CMD+Z

Hoewel ik niet het gevoel heb het hele probleem helemaal te overzien, vind ik dat het sowieso netter zou zijn als post.exe in ieder geval resident is in plaats van dat hij steeds opnieuw opstart, hoe je dat dan ook verder oplost. Een Service zou de meest voor de hand liggende optie zijn.

iOS developer


Acties:
  • 0 Henk 'm!

  • Haan
  • Registratie: Februari 2004
  • Laatst online: 20:53

Haan

dotnetter

BikkelZ schreef op maandag 06 februari 2012 @ 15:54:
Hoewel ik niet het gevoel heb het hele probleem helemaal te overzien, vind ik dat het sowieso netter zou zijn als post.exe in ieder geval resident is in plaats van dat hij steeds opnieuw opstart, hoe je dat dan ook verder oplost. Een Service zou de meest voor de hand liggende optie zijn.
Een service zou ik niet direct de meest voor de hand liggende optie noemen. Met de eerder genoemde Mutex, kan je ook gewoon 1 instance van pots.exe afdwingen. Zie bijvoorbeeld hier

Kater? Eerst water, de rest komt later


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 16-09 09:15

Janoz

Moderator Devschuur®

!litemod

1 instantie op de client? Het lijkt mij toch echt beter om het op de server af te handelen. Integriteit op de client afdwingen kan in dit geval nog werken omdat er maar 1 client is, maar de server lijkt mij juist de aangewezen plek.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • L-VIS
  • Registratie: April 2005
  • Laatst online: 17-09 16:00
Hydra schreef op maandag 06 februari 2012 @ 14:40:
Maar vertel nu eens waarom je niet gewoon DateTime.Now mee kunt inserten als het 'probleem' is dat er meerdere processen tegelijkertijd gestart worden? Kan me niet voorstellen dat dat in dezelfde milliseconde gebeurt.
Omdat de resolutie minimaal 10 miliseconden is!

Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
L-VIS schreef op maandag 06 februari 2012 @ 16:43:
Omdat de resolutie minimaal 10 miliseconden is!
Je zit er een factor 100.000 naast. De werkelijke resolutie is 100 nanoseconden. Probeer maar eens in de debugger:
C#:
1
2
        for (int i = 0; i < 100; i++)
            Console.WriteLine(DateTime.Now.Ticks);

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • Haan
  • Registratie: Februari 2004
  • Laatst online: 20:53

Haan

dotnetter

Janoz schreef op maandag 06 februari 2012 @ 16:19:
1 instantie op de client? Het lijkt mij toch echt beter om het op de server af te handelen. Integriteit op de client afdwingen kan in dit geval nog werken omdat er maar 1 client is, maar de server lijkt mij juist de aangewezen plek.
Ik zou voor beiden gaan. Voor de client lijkt het me niet ideaal als er steeds post.exe processen gespawned worden. Afdwingen van integriteit kan je inderdaad beter op de server afhandelen.

Kater? Eerst water, de rest komt later


Acties:
  • 0 Henk 'm!

  • L-VIS
  • Registratie: April 2005
  • Laatst online: 17-09 16:00
pedorus schreef op maandag 06 februari 2012 @ 16:54:
[...]

Je zit er een factor 100.000 naast. De werkelijke resolutie is 100 nanoseconden. Probeer maar eens in de debugger:
C#:
1
2
        for (int i = 0; i < 100; i++)
            Console.WriteLine(DateTime.Now.Ticks);
Dat is heel gek want hier staat het volgende:
The Now property is frequently used to measure performance. However, because of its low resolution, it is not suitable for use as a benchmarking tool. A better alternative is to use the Stopwatch class.
En als ik jou code uitvoer krijg ik toch echt een hoop dezelfde ticks ;)

Acties:
  • 0 Henk 'm!

  • Jitse H
  • Registratie: Mei 2011
  • Laatst online: 19:54
Janoz schreef op maandag 06 februari 2012 @ 11:01:
TS praat over het in de verkeerde volgorde aankomen van de berichten, maar als ik Jitse H in "\[C#] Invoer volgorde aanhouden in de database" lees dan denk ik dat hij eigenlijk een heel ander probleem bedoeld.

Het is niet de volgorde, maar een raceprobleem. Twee berichten die tegelijk komen zien elkaar nog niet in de database waardoor ze niet gekoppeld kunnen worden. De plek waar dit opgelost moet worden is niet in de post.exe, maar op de server. Eerste wat bij mij opkomt is inderdaad een queue gebruiken, maar aangezien je op de server met php werkt heb je die niet tot je beschikking. Wat je ook kunt doen is je model iets verder normalizeren. de 'a' en 'b' neem je op in een aparte tabel met daarop een unique constraint. Bij het inserten krijgt 1 van beiden dan vanzelf een unique constraint violation en kan vervolgens alsnog de berichten koppelen.
Wat een reacties al, super!

Nu ik het teruglas, heb ik inderdaad het probleem niet helemaal goed beschreven. Het is inderdaad een `race` probleem :) Heb de TS al even wat aangepast.

Volgens mij kan "Wat je ook kunt doen is je model iets verder normalizeren. de 'a' en 'b' neem je op in een aparte tabel met daarop een unique constraint." niet, ik heb namelijk de volgende situatie:

10:15:01 Testbericht 1 A
10:15:01 Testbericht 2 A
10:15:02 Testbericht 3 A
10:15:02 Testbericht 4 A

10:16:05 Testbericht 5 A
10:16:05 Testbericht 6 A
10:16:05 Testbericht 7 A

De berichten 1 t/m 4 moet aan elkaar gekoppeld worden en de berichten 5 t/m 7 ook.
Dit koppelen gebeurt door het script wat op de server draait. Deze bekijkt bij "Testbericht 1" als hij afgelopen X aantal seconden al eerder een bericht voor "A" heeft gehad. Dit is nu niet het geval.
Dit zelfde herhaalt zich bij de andere berichten, Bij testbericht 2 zie hij dus dan dat "testbericht 1" er al is geweest binnen de X aantal seconden en ook met "A". Nu gaat hij dus het ID van testbericht 1 in het koppelveld van testbericht 2 zetten. Dit laatste herhaalt zich dus ook voor bericht 3 en 4.

Bericht 5,6,7, vallen buiten de X aantal seconden, maar vallen hier samen wel binnen. Deze zullen dus ook aan elkaar gekoppeld worden, maar niet aan 1t/m4.

Het probleem is dus inderdaad dat als ze elkaar niet zien bij het toevoegen, de berichten niet gekoppeld worden maar dat er 2 koppelingen zijn. Een cronjob verhelpt dit op dit moment, maar dat moet eigenlijk direct goed.

==========================================================

Als ik de link van Haan volg dan kom ik uit op dit stuk code:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void Main() {    
  bool ownsMutex;      
  
  using (Mutex mutex =new Mutex(true, "MutexExample", out ownsMutex))     
  {         
    if (ownsMutex)         
    {             
      Console.WriteLine("Owned");             
      mutex.ReleaseMutex();         
    } else  {             
      Console.WriteLine("Another instance of this application " +                 
           " already owns the mutex named MutexExample.");         
    }     
  } 
}


Maar als ik dit toepas zullen er berichten die worden verstuurd terwijl het proces nog actief is ( dus de else bereiken ), dus niet meer worden verzonden. Hierdoor zou ik dus ook nog een queue moeten gebruiken zodat ze blijven wachten? Of kan dit anders?

Acties:
  • 0 Henk 'm!

  • BikkelZ
  • Registratie: Januari 2000
  • Laatst online: 21-02 08:50

BikkelZ

CMD+Z

Haan schreef op maandag 06 februari 2012 @ 16:02:
[...]

Een service zou ik niet direct de meest voor de hand liggende optie noemen. Met de eerder genoemde Mutex, kan je ook gewoon 1 instance van pots.exe afdwingen. Zie bijvoorbeeld hier
Nee wat ik dan waarschijnlijk zou willen is één service op de server, en één instance op de client. Die service moet gewoon klaarstaan om alle berichten direct te verwerken, dan moet je niet met een los op te starten .exe te maken hebben.

iOS developer


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
L-VIS schreef op maandag 06 februari 2012 @ 17:14:
En als ik jou code uitvoer krijg ik toch echt een hoop dezelfde ticks ;)
offtopic:
Als je dat bij een StopWatch doet zie je dat ook, dat komt omdat je binnen 100 nanosec best wel een flink aantal instructies kan doen. Overigens is (1000L*1000L*1000L) / Stopwatch.Frequency bij mij hoger dan 100 nanosec, hoewel ik voor het gemak ook altijd een StopWatch gebruik voor timings.
Jitse H schreef op maandag 06 februari 2012 @ 20:01:
Maar als ik dit toepas zullen er berichten die worden verstuurd terwijl het proces nog actief is ( dus de else bereiken ), dus niet meer worden verzonden. Hierdoor zou ik dus ook nog een queue moeten gebruiken zodat ze blijven wachten? Of kan dit anders?
Ik zou geen queue en synchronisatie gebruiken, maar net als bijv. Chrome gewoon meerdere processen laten bestaan. Dus de webrequest neerzetten waar hasHandle zeker true is in http://stackoverflow.com/...using-a-global-mutex-in-c


Maar eigenlijk is een oplossing op de server mooier. Waarschijnlijk is het prima op te lossen door gebruik te maken van atomic-zaken die MySQL biedt, een beetje afhankelijk van performance-eisen (ivm locks) en hoe je precies wil clusteren. In de simpelste vorm (alleen inserten als niet al gelogd) is het slechts een kwestie van je insert statement vervangen naar een insert into ... select ... where not exists ....

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • CodeCaster
  • Registratie: Juni 2003
  • Niet online

CodeCaster

Can I get uhm...

Jitse H schreef op maandag 06 februari 2012 @ 20:01:
ik heb namelijk de volgende situatie:

10:15:01 Testbericht 1 A
10:15:01 Testbericht 2 A
10:15:02 Testbericht 3 A
10:15:02 Testbericht 4 A

10:16:05 Testbericht 5 A
10:16:05 Testbericht 6 A
10:16:05 Testbericht 7 A

De berichten 1 t/m 4 moet aan elkaar gekoppeld worden en de berichten 5 t/m 7 ook.
Dit koppelen gebeurt door het script wat op de server draait. Deze bekijkt bij "Testbericht 1" als hij afgelopen X aantal seconden al eerder een bericht voor "A" heeft gehad. Dit is nu niet het geval.
Dit zelfde herhaalt zich bij de andere berichten, Bij testbericht 2 zie hij dus dan dat "testbericht 1" er al is geweest binnen de X aantal seconden en ook met "A". Nu gaat hij dus het ID van testbericht 1 in het koppelveld van testbericht 2 zetten. Dit laatste herhaalt zich dus ook voor bericht 3 en 4.

Bericht 5,6,7, vallen buiten de X aantal seconden, maar vallen hier samen wel binnen. Deze zullen dus ook aan elkaar gekoppeld worden, maar niet aan 1t/m4.

Het probleem is dus inderdaad dat als ze elkaar niet zien bij het toevoegen, de berichten niet gekoppeld worden maar dat er 2 koppelingen zijn.
Dit verhaal is een requirement die je beter moet gaan specificeren. Als je dat lukt, is de technische oplossing een eitje.

Is dat 'aantal seconden' bijvoorbeeld afhankelijk van het eerste of juist het laatst ontvangen bericht met "A"?

In het eerste geval zou je een koppeling kunnen maken met "10:15:01 | A", op het moment dat je het eerste bericht ontvangt. Deze sla je op in een koppeltabel, en ieder bericht dat binnen X seconden wordt ontvangen vanaf 10:15:01 met payload "A", link je aan dat item in de koppeltabel.

Ontvang je dan een bericht dat buiten je X seconden valt, dan maak je een nieuwe relatie aan ("10:16:05 | A"), en ga je de daaropvolgende berichten koppelen aan die relatie.

Als het aantal seconden afhankelijk is van het laatst ontvangen bericht per 'koppeling', dan zou je een update kunnen doen op je koppeltabel als er aan de voorwaarde van "binnen X seconden" is voldaan; zo niet, dan maak je weer een nieuw record aan, en update je dat bij ieder opvolgend bericht.

Je DBMS kan zorgen dat dit atomair gebeurt. Dus, psuedocode aan de databasekant voor situatie 1:
code:
1
2
3
4
1. Ontvang bericht met tijdstip A en payload B.
2. Zoek het ID in de koppeltabel bij record met payload = B en tijdstip A >= (nu - X seconden). Indien niet gevonden:
2a. Insert record A|B in koppeltabel, bewaar ID.
3. Sla nu de overige informatie op in je andere tabel, koppel aan de koppeltabel met ID


Situatie 2:
code:
1
2
3
4
5
1. Ontvang bericht met tijdstip A en payload B.
2. Zoek het ID in de koppeltabel bij record met payload = B en tijdstip A >= (nu - X seconden). Indien niet gevonden (a), indien wel gevonden (b):
2a. Insert record A|B in koppeltabel, bewaar ID.
2b. Update record met ID=ID, zet tijdstip A op nu. 
3. Sla nu de overige informatie op in je andere tabel, koppel aan de koppeltabel met ID

https://oneerlijkewoz.nl
Op papier is hij aan het tekenen, maar in de praktijk...


Acties:
  • 0 Henk 'm!

  • Jitse H
  • Registratie: Mei 2011
  • Laatst online: 19:54
Ik zal morgen proberen om even in te gaan op de andere posts, maar die post van CodeCaster wil ik nu wel even op reageren;

Zo'n systeem

1. Ontvang bericht met tijdstip A en payload B.
2. Zoek het ID in de koppeltabel bij record met payload = B en tijdstip A >= (nu - X seconden).
Indien niet gevonden:
2a. Insert record A|B in koppeltabel, bewaar ID.
3. Sla nu de overige informatie op in je andere tabel, koppel aan de koppeltabel met ID

gebruik ik nu. Er wordt nu ook eerst gekeken of er al een bericht in de database staat met dezelfde gegevens. Alleen ik zie nu dat in de loop van de tijd dat sommige berichten niet gekoppeld worden. Draai ik dan vervolgens een cronjob met dezefde checks dan wordt hij wel gekoppeld. Het lijkt mij dan, dat ze elkaar niet zien tijdens het toevoegen waardoor ze niet aan elkaar gekoppeld worden.

Acties:
  • 0 Henk 'm!

  • Rotterdammertje
  • Registratie: Juni 2002
  • Laatst online: 28-03-2023
Het lijkt mij dat je met een table lock er misschien wel uit komt. Het proces loopt dan ongeveer als volgt:

1. Ontvang bericht met tijdstip A en payload B
2. Zoek het ID in de koppeltabel met payload B en tijdstip >= (nu - X seconden)
3a. Koppel indien gevonden

Indien niet gevonden:
3b. Lock koppeltabel voor schrijven
4. Zoek nogmaals het ID in de koppeltabel met payload B en tijdstip >= (nu - X seconden) -- tussen stap 2 en 3b kan een ander proces een record hebben aangemaakt!
5a. Indien gevonden, koppel
5b. Indien niet gevonden, maak record aan
6. Unlock tabel

Dit zorgt ervoor dat altijd maar 1 proces tegelijk records kan aanmaken in de koppeltabel; ook wordt de tabel niet onnodig gelocked.

main = putStr (q ++ show q); q = "main = putStr (q ++ show q); q = "


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Lock is nogal overkill lijkt mij. Voorbeeldje:
SQL:
1
2
3
4
create table payloads(id int auto_increment primary key, payload varchar(200), 
    time datetime);
insert into payloads(payload, time) select "A", now() from dual where not exists 
    (select * from payloads where payload="A" and time >= now() - interval 10 second);


2e query maakt hier maximaal eens per 10s een id aan, ook als je meerdere sessies op start. now() moet je natuurlijk vervangen door de tijd van je berichtje, en na afloop van de query kun je de id selecteren.

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • Rotterdammertje
  • Registratie: Juni 2002
  • Laatst online: 28-03-2023
pedorus schreef op donderdag 09 februari 2012 @ 11:18:
Lock is nogal overkill lijkt mij. Voorbeeldje:
SQL:
1
2
3
4
create table payloads(id int auto_increment primary key, payload varchar(200), 
    time datetime);
insert into payloads(payload, time) select "A", now() from dual where not exists 
    (select * from payloads where payload="A" and time >= now() - interval 10 second);
Met de aanname dat er geen twee INSERT .. SELECT statements tegelijk uitgevoerd worden. Is dit gedocumenteerd gedrag? Anders loop je alsnog het risico dat twee processen tegelijk een insert uitvoeren.

main = putStr (q ++ show q); q = "main = putStr (q ++ show q); q = "


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
In principe wordt 1 sql-statement atomair uitgevoerd. Ik neem aan dat MySQL conformant is. http://stackoverflow.com/...sert-conditioned-on-count bijv. lijkt dit te suggereren in dit specifieke geval.

Voor MyISAM vind ik het maar een vaag verhaal http://dev.mysql.com/doc/...si-diff-transactions.html , InnoDB zou goed moeten gaan.

Voor SQL Server gaat dit niet goed zonder lock trouwens: http://stackoverflow.com/...tions-in-sql-server-it-en Misschien toch eerst eens uitproberen ;)

[ Voor 48% gewijzigd door pedorus op 09-02-2012 14:13 ]

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • YopY
  • Registratie: September 2003
  • Laatst online: 13-07 01:14
Zomaar een vraagje, op welk moment moeten de entries gegroepeerd worden? Want het lijkt mij logischer (puur op basis van wat de TS heeft laten zien) om gewoon alle data die post.exe in de database gooit 'as-is' te houden, en pas als een gebruiker het weer uitleest het te groeperen op tijd. Het groeperen op tijd lijkt me 'groepjes die minstens X seconden van elkaar af staan', en dat zou met een SQL query te doen moeten zijn, danwel in code (code lijkt me eenvoudiger).

Acties:
  • 0 Henk 'm!

  • Big Womly
  • Registratie: Oktober 2007
  • Laatst online: 01-09 13:39

Big Womly

Live forever, or die trying

Heb niet het hele topic doorgenomen, maar naast de tijd meesturen zou ik ook voorstellen op op Post.exe het singleton/double checked locking pattern toe te passen en een message queue te implementeren.

When you talk to God it's called prayer, but when God talks to you it's called schizophrenia


Acties:
  • 0 Henk 'm!

Verwijderd

Ik zie mijn voorgangers met allerlij oplossing komen als message queues, locking en datetime thicks meegeven.

Maar volgens mij is jouw probleem iets eenvoudiger op te lossen.

In je post.exe app:
- Als je een bericht wil posten, welke een relatie heeft met een ander bericht dat NIET gevonden kan worden:
post het bericht naar een tijdelijke tabel 'tabel_queue?' en sluit af.

- elke keer als post.exe opstart, controleer de 'tabel_queue' of daar een bericht wacht op het 'master bericht'.
ala:
SELECT FROM queue q WHERE q.RelatedMsgId = @postedMessageId

komt hier iets uit. Post dan eerst het bericht uit de queue (en verwijder uit queue), en post daarna het nieuwe bericht zoals meegegeven aan post.exe.

In deze volgorde zullen alle berichten die eerder aankomen dan het 'hoofdbericht' eerst in de queue komen, en daar blijven totdat het hoofdbericht binnenkomt.
Als het hoofdbericht binnenkomt, worden alle 'wachtende' subberichten uit de queue gehaald en alsnog verwerkt.

Met een klein beetje extra logica kan je dit ook werkend krijgen voor sub / sub sub berichten, etc.

Hoop dat dit helpt.

Remco
Pagina: 1