Frage zu Blocking.pm

Begonnen von DS_Starter, 27 Mai 2016, 22:51:32

Vorheriges Thema - Nächstes Thema

DS_Starter

Hallo zusammen,

ich habe nun schon einiges mit blocking.pm gebaut, habe aber gerade einen Effekt den ich mir nicht erklären kann. Ich hoffe ihr habt eine Idee.

Folgende subs habe ich gebaut um nonblocking selects und deletes auf MySQL abzusetzen (Auszug):

..........
# SQL zusammenstellen
         my $sql = "SELECT DEVICE,READING,TIMESTAMP,VALUE FROM history where ";
         $sql .= "READING = '$reading' AND " if($reading);
         $sql .= "DEVICE = '$device' AND " if($device);
         $sql .= "TIMESTAMP BETWEEN ? AND ? ORDER BY TIMESTAMP;";   
     
         Log3($name, 4, "DbRep $name - SQL to execute: $sql");   
         
         my $sth = $dbh->prepare($sql); 
         $hash->{HELPER}{FRSTH} = $sth;
             
         $hash->{helper}{FR_RUNNING_PID} = BlockingCall("fetchrows_DoParse", "$name|$runtime_string_first|$runtime_string_next", "fetchrows_ParseDone", 60, "fetchrows_ParseAborted", $hash);

########################################################################

sub fetchrows_DoParse {
my ($string) = @_;
my ($name, $runtime_string_first, $runtime_string_next) = split("\\|", $string);
my $hash         = $defs{$name};
my $dbh          = $hash->{dbloghash}{DBH};
my $sth          = $hash->{HELPER}{FRSTH};

Log3 $name, 4, "$name -> Start BlockingCall fetchrows_DoParse";
sleep(1);

$sth->execute($runtime_string_first, $runtime_string_next);

my @row_array = map { $_ -> [0]." ".$_ -> [1]." ".$_ -> [2]." ".$_ -> [3]."\n" } @{ $sth->fetchall_arrayref() };
$sth->finish();

my $rowlist = join('|', @row_array);
Log3 $name, 5, "$name -> row_array:  @row_array";

# Daten müssen als Einzeiler zurückgegeben werden
$rowlist = encode_base64($rowlist,"");

Log3 $name, 4, "$name -> BlockingCall fetchrows_DoParse finished";

return "$name|$rowlist";
}

####################################################################################################
# Auswertungsroutine der nichtblockierenden DB-Abfrage
####################################################################################################

sub fetchrows_ParseDone {
  my ($string) = @_;
  my @a = split("\\|",$string);
  my $hash = $defs{$a[0]};
  my $name = $hash->{NAME};
  my @i;
  my @row;
 
  my $rowlist     = decode_base64($a[1]);
  my $reading     = AttrVal($hash->{NAME}, "reading", undef);
  my $reading_runtime_string;
 
  Log3 $hash->{NAME}, 4, "$hash->{NAME} -> Start BlockingCall fetchrows_ParseDone";
 
  my @row_array = split("\\|", $rowlist);
 
  Log3($name, 5, "DbRep $name - row_array: @row_array");
 
  foreach my $row (@row_array) {
             my @a = split("[ \t][ \t]*", $row);
             my $dev = $a[0];
             my $rea = $a[1];
             my $ts  = $a[2]." ".$a[3];
             my $val = $a[4];
             
             # Readingaufbereitung
             if ($reading && AttrVal($hash->{NAME}, "readingmap", "")) {
                 $reading_runtime_string = $ts." -- ".AttrVal($hash->{NAME}, "readingmap", "");
             } else {
                 $reading_runtime_string = $ts." -- ".$dev." -- ".$rea;
             }
             
             # readingsBulkUpdate($hash, $reading_runtime_string, $val);
             readingsSingleUpdate($hash, $reading_runtime_string, $val, 1);
  }
             
readingsSingleUpdate($hash, "state", "done", 1);

  # Browser mit Raumansichten neu laden
  # map {FW_directNotify("#FHEMWEB:$_", "location.reload(true)", "")} devspec2array("WEB.*");
 
  Log3 $hash->{NAME}, 4, "$hash->{NAME} -> BlockingCall fetchrows_ParseDone finished";
  delete($hash->{helper}{FR_RUNNING_PID});
 
return;
}

......................


Es funktioniert alles ganz einwandfrei, aber nur wenn ich den "sleep(1)" in der Routine "fetchrows_DoParse " einfüge.
Mache ich das nicht, funktioniert zwar das SQL-Statement (sehe ich im Logfile), aber FHEMWEB hängt sich auf, d.h. die Eieruhr arbeitet.  Es sieht so aus als ob "fetchrows_DoParse " bis zum Ende abgearbeitet wird, aber keine Weiterverarbeitung erfolgt.

Wie gesagt mit der kleinen Zeitverzögerung durch sleep klappt alles tadellos und ich habe dadurch einen Workaround.

Vielleicht habt ihr eine Idee ohne das sleep auszukommen, bisher hatte ich diesen Effekt noch nicht.

Gruß
Heiko
Proxmox+Debian+MariaDB, PV: SMA, Victron MPII+Pylontech+CerboGX
Maintainer: SSCam, SSChatBot, SSCal, SSFile, DbLog/DbRep, Log2Syslog, SolarForecast,Watches, Dashboard, PylonLowVoltage
Kaffeekasse: https://www.paypal.me/HMaaz
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter

rudolfkoenig

Bei diesem Szenario faellt mir ein, dass fork mit DB-Verbindungen Probleme hat, da per default die Perl-DB-Library bei einem Exit (auch des Clients) die DB-Verbindung zu macht. In fhemFork wird fuer DbLog Instanzen extra InactiveDestroy gesetzt (Hmm. Eigentlich muesste das das DbLog Modul selbst machen...).
Ich wuerde die DB Verbindung in BlockingCall oeffnen und zumachen, um weniger Stress auch mit anderen forks zu haben.

DS_Starter

Hallo Rudi,

danke für deinen Hinweis !  Schaue ich mir an. Ich bin noch beim basteln und probieren. Der letzte Schuß ist das bestimmt noch nicht. Es läuft schon ganz gut, aber nicht perfekt.
Nur mit der sleep-Problematik kann das doch m.M. eigentlich nichts zu tun haben, nach dem fork müßte der Hauptprozess doch wieder zurückkommen, auch ohne das sleep. Das macht er ja in aderen Fällen bei  mir auch . Nur in diesem speziellen Fall klappt das nicht und ich kann es mir einfach nicht erklären.
Proxmox+Debian+MariaDB, PV: SMA, Victron MPII+Pylontech+CerboGX
Maintainer: SSCam, SSChatBot, SSCal, SSFile, DbLog/DbRep, Log2Syslog, SolarForecast,Watches, Dashboard, PylonLowVoltage
Kaffeekasse: https://www.paypal.me/HMaaz
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter

DS_Starter

Hallo Rudi,

kleines Update ... habe die blocking-subs so umgebaut wie von dir vorgeschlagen. Also in dieser Art:

sub sumval_DoParse {
... Variablen Init....
my $dbh = DBI->connect_cached("dbi:$dbconn", $dbuser, $dbpassword, { PrintError => 0, AutoInactiveDestroy => 1 });

....do something ...

$dbh->disconnect;
}


Läuft bis jetzt tadellos ... und auch ohne das "sleep" .   :)
Wahrscheinlich braucht man an dieser Stelle das "AutoInactiveDestroy" garnicht, aber habe momentan keine Zeit weiter zu testen. Ich lasse es erstmal so.

Wieder ein Problem gelöst .. danke !

Grüße
Heiko
Proxmox+Debian+MariaDB, PV: SMA, Victron MPII+Pylontech+CerboGX
Maintainer: SSCam, SSChatBot, SSCal, SSFile, DbLog/DbRep, Log2Syslog, SolarForecast,Watches, Dashboard, PylonLowVoltage
Kaffeekasse: https://www.paypal.me/HMaaz
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter