ending transaction with Yii::app()->end - yii

yii 1
Will Mysql Innodb transaction also end after Yii::app()->end() ?
Here based on model validation an error is being returned to javascript :
begin transaction
if (!$model->save()) {
echo CJSON::encode(array(
"error"=>true,
"errorDetails" => $model->getErrors(),
"code"=>"500"
));
Yii::app()->end();
}
end transaction
Can we find active transactions for Yii::app() and end live transaction in above case since it will otherwise leave transaction open
Yii::app()->onEndRequest = function($event){
//Find active transaction for current request and db and rollback
};

This solved it in index.php
$app = Yii::createWebApplication($config);
Yii::app()->onEndRequest = function($event){
if(!is_null(Yii::app()->db->getCurrentTransaction())) {
Yii::app()->db->getCurrentTransaction()->rollback();
}
};
$app->run();

Related

How to execute multiple QueryBuilders in a transaction using TypeORM

I have multiple queries that I created using QueryBuilder, I wanted to execute all of these queries inside a single transaction.
I read the documentation but it lacks information on how to use a QueryBuilder with transactions. I tried to create my queries using the same QueryRunner manager but I really feel like this does nothing.
I also tried to wrap my method using a #Transaction decoration but I get a socket hang up error.
This is my current attempt, I only added 2 queries in the example but I have 5 in total.
let user, membersInstituition
const connection = getConnection()
const queryRunner = connection.createQueryRunner()
console.log(queryRunner.isTransactionActive) // false
await queryRunner.startTransaction()
try {
console.log(queryRunner.isTransactionActive) // true
user = await queryRunner.manager
.createQueryBuilder(Usuarios, 'user')
.leftJoin(UltimaAtualizacaoMobile, 'att', 'user.id_usuario = att.id_usuario')
.select(['user.id_usuario as idUser, user.nome as name, att.ultima_atualizacao as ultimaAtualizacaoMobile'])
.where('user.id_usuario = :idUsuario', { idUsuario: idUsuario })
.execute()
membersInstituition = await queryRunner.manager
.createQueryBuilder(Instituicoes, 'insti')
.leftJoin(Amostras, 'am', 'am.id_instituicao = insti.id_instituicao')
.leftJoin(MembrosInstituicao, 'mi', 'mi.id_instituicao = insti.id_instituicao')
.leftJoin(Permissoes, 'perm', 'perm.id_permissao = mi.id_permissao')
.leftJoin(MembrosAmostra, 'mam', 'mam.id_amostra = am.id_instituicao AND mam.id_membro_instituicao = mi.id_membro_instituicao')
.where('am.id_amostra IN (:...idAmostras)', { idAmostras: idAmostras })
.andWhere('mi.id_usuario = :idUsuario', { idUsuario: idUsuario })
.select('mi.id_membro_instituicao as idMember, mam.id_membro_amostra as idMemberAmostra, insti.id_instituicao as idInstituition, perm.permissao as userPermission')
.orderBy('insti.id_instituicao', 'ASC')
.execute()
await queryRunner.commitTransaction()
console.log(queryRunner.isTransactionActive) // false
} catch (error) {
// Handle error
} finally {
await queryRunner.release()
}
Above code is indeed working, confirmed using TypeORM's logging, it shows the transaction starting and all the following queries before committing.
More info on how to enable Logging and to verify if your queries are under the same transaction: https://github.com/typeorm/typeorm/blob/master/docs/logging.md

BigQuery php client library queryresult shows isComplete false. But I can confirm the query is successful

$queryResults = $this->bigQuery->runQuery($query, ['parameters' => ['id' => $id]]);
$info = $queryResults->info();
var_dump($info);
// var_dump($queryResults);
$isComplete = $queryResults->isComplete();
if ($isComplete) {
exit("Insert. Done!");
}
The query is a "insert select" statement. which I had run successful on bigquery cloud console directly.
When I use php client library here, the query finished successful too and I can confirm that it is the same as I run query directly on google cloud console.
But the info of the query shows isComplete false.
array(3) {
["kind"]=>
string(22) "bigquery#queryResponse"
["jobReference"]=>
array(2) {
["projectId"]=>
string(26) "myprojectid"
["jobId"]=>
string(31) "job_OHcckVSSwAI7pHXijmmUqK5H4XE"
}
["jobComplete"]=>
bool(false)
}
There are no errors report form the $queryResults->info();. How could I find out why it shows me isComplete false?
Probably you still need to run $queryResults -> reload() to update the job status. As in the docs:
$isComplete = $queryResults->isComplete();
while (!$isComplete) {
sleep(1); // small delay between requests
$queryResults->reload();
$isComplete = $queryResults->isComplete();
}

PDO doesn't work when updating multiple rows with transactions

I'm gonna execute multiple rows of a table in same time with an instance of pdo.
I tried this :
try {
$pdo->beginTransaction();
$query = $pdo->prepare('UPDATE forum_config SET config_value = ? WHERE config_name = ?');
$query->execute(array('activate_avatar', $_POST['activate_avatar']));
$query->execute(array('activate_mp', $_POST['activate_mp']));
$query->execute(array('activate_sign', $_POST['activate_sign']));
$query->execute(array('allow_register', $_POST['allow_register']));
$query->execute(array('avatar_max_height', $_POST['avatar_max_height']));
$query->execute(array('avatar_max_size', $_POST['avatar_max_size']));
$query->execute(array('avatar_max_width', $_POST['avatar_max_width']));
$query->execute(array('cookies_expires', $_POST['cookies_expires']));
$query->execute(array('domain_name', $_POST['domain_name']));
$query->execute(array('forum_style', $_POST['forum_style']));
$query->execute(array('post_flood_time', $_POST['post_flood_time']));
$query->execute(array('post_max_size', $_POST['post_max_size']));
$query->execute(array('post_max_smilies', $_POST['post_max_smilies']));
$query->execute(array('session_time_out', $_POST['session_time_out']));
$query->execute(array('sign_max_size', $_POST['sign_max_size']));
$query->execute(array('site_closed_reason', $_POST['site_closed_reason']));
$query->execute(array('site_open', $_POST['site_open']));
$query->execute(array('topic_flood_time', $_POST['topic_flood_time']));
$query->execute(array('topic_max_size', $_POST['topic_max_size']));
$pdo->commit();
}
catch(Exception $e) {
$pdo->rollback();
die('Erreur : '.$e->getMessage());
}
unset($query);
But it doesn't do anything. What is the problem? Thanks for your help

matching and verifying Express 3/Connect 2 session keys from socket.io connection

I have a good start on a technique similar to this in Express 3
http://notjustburritos.tumblr.com/post/22682186189/socket-io-and-express-3
the idea being to let me grab the session object from within a socket.io connection callback, storing sessions via connect-redis in this case.
So, in app.configure we have
var db = require('connect-redis')(express)
....
app.configure(function(){
....
app.use(express.cookieParser(SITE_SECRET));
app.use(express.session({ store: new db }));
And in the app code there is
var redis_client = require('redis').createClient()
io.set('authorization', function(data, accept) {
if (!data.headers.cookie) {
return accept('Sesssion cookie required.', false)
}
data.cookie = require('cookie').parse(data.headers.cookie);
/* verify the signature of the session cookie. */
//data.cookie = require('cookie').parse(data.cookie, SITE_SECRET);
data.sessionID = data.cookie['connect.sid']
redis_client.get(data.sessionID, function(err, session) {
if (err) {
return accept('Error in session store.', false)
} else if (!session) {
return accept('Session not found.', false)
}
// success! we're authenticated with a known session.
data.session = session
return accept(null, true)
})
})
The sessions are being saved to redis, the keys look like this:
redis 127.0.0.1:6379> KEYS *
1) "sess:lpeNPnHmQ2f442rE87Y6X28C"
2) "sess:qsWvzubzparNHNoPyNN/CdVw"
and the values are unencrypted JSON. So far so good.
The cookie header, however, contains something like
{ 'connect.sid': 's:lpeNPnHmQ2f442rE87Y6X28C.obCv2x2NT05ieqkmzHnE0VZKDNnqGkcxeQAEVoeoeiU' }
So now the SessionStore and the connect.sid don't match, because the signature part (after the .) is stripped from the SessionStore version.
Question is, is is safe to just truncate out the SID part of the cookie (lpeNPnHmQ2f442rE87Y6X28C) and match based on that, or should the signature part be verified? If so, how?
rather than hacking around with private methods and internals of Connect, that were NOT meant to be used this way, this NPM does a good job of wrapping socket.on in a method that pulls in the session, and parses and verifies
https://github.com/functioncallback/session.socket.io
Just use cookie-signature module, as recommended by the comment lines in Connect's utils.js.
var cookie = require('cookie-signature');
//assuming you already put the session id from the client in a var called "sid"
var sid = cookies['connect.sid'];
sid = cookie.unsign(sid.slice(2),yourSecret);
if (sid == "false") {
//cookie validation failure
//uh oh. Handle this error
} else {
sid = "sess:" + sid;
//proceed to retrieve from store
}

How can I alert Skype chatrooms with Jenkins build status?

Our company uses Skype for communications, and I'd like to be able to send alerts to Skype chatrooms when a Jenkins build fails (and when it recovers too).
How can I do this?
I've done this using the Skype Public API
What I did was write a Perl script which uses the SkypeAPI CPAN module to handle the communications with Skype. It's a little clunky, as the script needs to run on a desktop which is running Skype. I run it on my own desktop which is always on anyway, but this does mean the bot appears to be 'me' to the rest of our team.
The end result is fantastic - whenever a jenkins build changes state, the bot sends a message to any Skype chats which have registered an interest by typing *alert. Additionally, any developer can see and share the latest build status by typing *jenkins
Step 1 - Extending the SkypeAPI module
Now, the SkypeAPI module is pretty basic. It has a message loop in the listen() method which checks for new events from the Skype client, and sleeps for a moment if there none.
I wanted my script to hook into this loop so that I could have my bot periodically check Jenkins RSS feed, so I made the following modifications to SkypeAPI.pm after I had installed it with the ActiveState package manager:
I declared new property 'idler' along with the existing properties...
__PACKAGE__->mk_accessors(
qw/api handler_list stop_listen idler/
);
I added a method to set an 'idler' callback which the module will call instead of sleeping
sub register_idler {
my $self = shift;
my $ref_sub = shift;
$self->idler($ref_sub);
}
Finally I modified the message loop to call the idler if set
sub listen {
my $self = shift;
my $idler=$self->idler();
$self->stop_listen(0);
while (!$self->stop_listen) {
my $message;
{
lock #message_list;
$message = shift #message_list;
}
if (not defined $message) {
if ($idler)
{
$self->idler->($self);
}
else
{
sleep 0.1;
}
next;
}
for my $id (sort keys %{$self->handler_list}) {
$self->handler_list->{$id}->($self, $message);
}
}
}
Step 2 - write a robot script
Now the module is a little more capable, it's just a matter of writing a script to act as a bot. Here's mine - I've made a few edits from my original as it contained other irrelevant functionality, but it should give you a starting point.
All of the dependant modules can be installed with the ActiveState package manager.
use strict;
use SkypeAPI;
use LWP::Simple;
use Data::Dumper;
use dirtyRSS;
use Time::Local 'timegm';
use Math::Round;
use Storable;
#CHANGE THIS - where to get jenkins status from
my $jenkinsRss='http://username:password#jenkins.example.com/rssLatest';
my %commands=(
'jenkins' =>\&cmdJenkins,
'alert' =>\&cmdAlert,
'noalert' =>\&cmdNoAlert,
'help' =>\&cmdHelp,
);
my $helpMessage=<<HELP;
Who asked for help? Here's all the other special commands I know...
*jenkins - show status of our platform tests
*alert - add this room to get automatic notification of build status
*noalert - cancel notifcations
*help - displays this message
HELP
#status for jenkins tracking
my %builds;
my $lastJenkinsCheck=0;
my $alertRoomsFile='alert.rooms';
my $alertRooms={};
#store jenkins state
checkJenkins();
#because that was our first fetch, we'll have flagged everything as changed
#but it hasn't really, so we reset those flags
resetJenkinsChangeFlags();
#remember rooms we're supposed to alert
loadAlertRooms();
#attach to skype and enter message loop
my $skype = SkypeAPI->new();
my $attached=$skype->attach();
$skype->register_handler(\&onEvent);
$skype->register_idler(\&onIdle);
$skype->listen();
exit;
#here are the command handlers
sub cmdJenkins
{
my ($chatId, $args)=#_;
my $message="";
foreach my $build (keys(%builds))
{
$message.=formatBuildMessage($build)."\n";
#reset changed flag - we've just show the status
$builds{$build}->{'changed'}=0;
}
chatmessage($chatId, $message);
}
sub cmdAlert
{
my ($chatId, $args)=#_;
addChatroomToAlerts($chatId,1);
}
sub cmdNoAlert
{
my ($chatId, $args)=#_;
addChatroomToAlerts($chatId,0);
}
sub cmdHelp
{
my ($chatId, $args)=#_;
chatmessage($chatId, $helpMessage);
}
#simple helper to transmit a message to a specific chatroom
sub chatmessage
{
my ($chatId, $message)=#_;
my $commandstr="CHATMESSAGE $chatId $message";
my $command = $skype->create_command( { string => $commandstr} );
$skype->send_command($command);
}
#refreshes our copy of jenkins state, and will flag any builds
#which have changed state since the last check
sub checkJenkins{
my $xml = get($jenkinsRss);
my $tree = parse($xml);
my $items=$tree->{'channel'}->[0]->{'item'};
foreach my $item (#{$items})
{
my $title=$item->{'title'};
my $link=$item->{'link'};
my $built=$item->{'lastbuilddate'};
#print Dumper($item);
if ($title=~m/^(.*?) #(\d+)\s*(.*)$/)
{
my $build=$1;
my $buildnumber=$2;
my $status=$3;
#print "$build\n$buildnumber\n$status\n$link\n$built\n\n";
#build in progress, ignore
if (!exists($builds{$build}))
{
$builds{$build}={};
$builds{$build}->{'status'}='';
$builds{$build}->{'changed'}=0;
}
$builds{$build}->{'name'}=$build;
if ($status eq '(?)')
{
$builds{$build}->{'in_progress'}=1;
next; #don't update until complete
}
else
{
$builds{$build}->{'in_progress'}=0;
}
#is this status different to last status?
if ($builds{$build}->{'status'} ne $status)
{
$builds{$build}->{'changed'}=1;
}
$builds{$build}->{'status'}=$status;
$builds{$build}->{'build_number'}=$buildnumber;
$builds{$build}->{'link'}=$link;
$builds{$build}->{'built'}=$built;
}
}
#print Dumper(\%builds);
}
#generates a string suitable for displaying build status in skype
sub formatBuildMessage
{
my ($build)=#_;
my $status=$builds{$build}->{'status'};
my $smiley=":)";
if ($status=~m/broken/)
{
$smiley="(devil)";
}
elsif ($status=~m/\?/)
{
#this means the build is being retested, we should skip it
$smiley=":|";
}
my $message='';
if ($builds{$build}->{'in_progress'})
{
$message=":| $build - rebuild in progress..."
}
else
{
my ($y,$mon,$d,$h,$m,$s) = $builds{$build}->{'built'} =~ m/(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)Z/;
my $time = timegm($s,$m,$h,$d,$mon-1,$y);
my $age=time()-$time;
my $mins=round($age/60);
my $hrs=round($age/3600);
my $days=round($age/86400);
my $niceage;
if ($mins<=2)
{
$niceage="a few moments ago";
}
elsif ($mins<120)
{
$niceage="$mins minutes ago";
}
elsif ($hrs<48)
{
$niceage="$hrs hours ago";
}
else
{
$niceage="$days days ago";
}
$message="$smiley $build last built $niceage $status";
}
return $message;
}
#forget any changes we've flagged
sub resetJenkinsChangeFlags
{
foreach my $build (keys(%builds))
{
$builds{$build}->{'changed'}=0;
}
}
#checks for builds which have changed state. Can be called
#often, it will only kick in if 60 seconds have elapsed since
#last check
sub checkForJenkinsChanges
{
my $now=time();
if (($now-$lastJenkinsCheck) < 60)
{
#no need, we fetched it recently
return;
}
checkJenkins();
my $message='';
foreach my $build (keys(%builds))
{
if ($builds{$build}->{'changed'})
{
$builds{$build}->{'changed'}=0;
$message.=formatBuildMessage($build)."\n";
}
}
if (length($message))
{
foreach my $chatId (keys(%$alertRooms))
{
chatmessage($chatId, $message);
}
}
$lastJenkinsCheck=$now;
}
#adds or removes a room from the alerts
sub addChatroomToAlerts
{
my($chatId, $add)=#_;
if ($add)
{
if (exists($alertRooms->{$chatId}))
{
chatmessage($chatId, "/me says this room is already getting alerts");
}
else
{
$alertRooms->{$chatId}=1;
chatmessage($chatId, "/me added this chatroom to jenkins alerts");
}
}
else
{
delete($alertRooms->{$chatId});
chatmessage($chatId, "/me removed this chatroom from jenkins alerts");
}
store $alertRooms, $alertRoomsFile;
}
sub loadAlertRooms
{
if (-e $alertRoomsFile)
{
$alertRooms = retrieve( $alertRoomsFile);
}
}
# Skype event handler
sub onEvent {
my $skype = shift;
my $msg = shift;
#my $command = $skype->create_command( { string => "GET USERSTATUS"} );
#print $skype->send_command($command) , "\n";
#print "handler: $msg\n";
#an inbound chat message is either
#MESSAGE 13021257 STATUS RECEIVED (from others)
#MESSAGE 13021257 STATUS SENT (from us)
if ($msg =~ m/MESSAGE (\d+) STATUS (SEND|RECEIVED)/)
{
my $msgId=$1;
#get message body
my $commandstr="GET CHATMESSAGE $msgId BODY";
my $command = $skype->create_command( { string => $commandstr} );
my $output=$skype->send_command($command);
#if its a message for us...
if ($output =~ m/MESSAGE $msgId BODY \*([^\s]*)\s*(.*)/i)
{
my $botcmd=$1;
my $botargs=$2;
$commandstr="GET CHATMESSAGE $msgId CHATNAME";
$command = $skype->create_command( { string => $commandstr} );
$output=$skype->send_command($command);
if ($output =~ m/MESSAGE $msgId CHATNAME (.*)/)
{
my $chatId=$1;
if (exists($commands{$botcmd}))
{
$commands{$botcmd}->($chatId, $botargs);
}
else
{
chatmessage($chatId, "/me suggests trying *help as the robot didn't understand *$botcmd");
}
}
}
}
}
#skype idle handler
#Note - SkypeAPI.pm was modified to support this
sub onIdle {
my $skype = shift;
checkForJenkinsChanges();
sleep 0.1;
}
Step 3 - Run the bot
If you've saved this as robot.pl, just open a console window and perl robot.pl should get it running. Skype will ask you if perl.exe should be allowed to communicate with it, and once you confirm that, you're good to go!
Go into a team chatroom and type *jenkins for an summary of latest builds, and register the room for alerts of build changes with *alert
Perfect :)
Though the answer provided above is a working solution, I think that is a bit old and no tools were available at the time the question was asked. There is a plugin available for Jenkins to integrate with skype:https://wiki.jenkins-ci.org/display/JENKINS/Skype+Plugin
This plugin can be used to send notification to a particular user or a group chat. I've been using it for a while and it works great. I primarily use linux servers for my Jenkins servers and I have a dedicated windows server with skype installed and logged in as a bot user. The only configuration needed for running skype in a slave is that it requires a label called "skype". With this label Jenkins will detect the slave and route skype notification to that slave.
One can use Sevabot (https://sevabot-skype-bot.readthedocs.org/) project to setup a HTTP based interface for Skype and then use Jenkin's Notification Plugin:
Example: https://sevabot-skype-bot.readthedocs.org/en/latest/jenkins.html