Using Perl's DBIx::Connector module on FastCGI web page - multithreading

Anyone has experience using the DBIx::Connector module for FastCGI pages? I googled around for a Perl implementation of DB Connection Pooling and found this DBIx::Connector module on CPAN which seems like it can be used for such functionality on FastCGI web pages. If you already had some experience using it, could you help clarifying some questions based on a sample script below? Any insight is greatly appreciated!
The global scoped $conn object is thread-safe and shared among all http's GET request threads inside the while loop ?
In each individual http's GET request thread, the $conn->dbh() method will either:
a. Return/Re-use an existing $dbh obj. if it already exists. OR:
b. Instantiate and return a brand new $dbh obj. if there's no existing ones?
In the case the DB server goes down and then goes back up, which causes $conn to disconnect, how do we re-establish/re-activate this global $conn object ? ( from what I understand about FastCGI, all global vars. above the while loop only get declared once on web-server startup, and only those inside the while loop are declared for every http GET request.. )
Example code:
use CGI::Fast;
use DBIx::Connector;
# Global var. for all http GET request threads
my $conn = DBIx::Connector->new( $dsn, $username, $password, {
RaiseError => 1,
AutoCommit => 1,
});
# Handling individual http GET request thread
while ( $q = CGI::Fast->new ) {
my $dbh = $conn->dbh ;
my $cursor1 = $dbh->prepare( sqlString1 ) ;
$cursor1->execute() ;
my $cursor2 = $dbh->prepare( sqlString2 ) ;
$cursor2->execute() ;
...
} #end individual http GET request thread

Related

How can I listen to webhooks from PayStack?

I created a website and I integrated payment using PayStack and it is fully functional, but something unusual came up sometime when a customer wanted to make a payment. After the successful payment processing, maybe something went wrong with the customer's Network provider but the customer was not redirected to a success page where to give values to database.
So I implemented webhooks to get values from paystack and PUT THE CONTENTS in a .txt (webhookApi.txt) file but it seems something is wrong with the code and I can't figure it out.
`
<?php
// only a post with paystack signature header gets our attention
if ((strtoupper($_SERVER['REQUEST_METHOD']) != 'POST' ) || !array_key_exists('x-paystack-signature', $_SERVER) )
exit();
// Retrieve the request's body
$input = #file_get_contents("php://input");
define('PAYSTACK_SECRET_KEY','sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxx');
// validate event do all at once to avoid timing attack
if($_SERVER['HTTP_X_PAYSTACK_SIGNATURE'] !== hash_hmac('HMAC SHA512', $input, PAYSTACK_SECRET_KEY))
exit();
http_response_code(200);
// parse event (which is json string) as object
// Do something - that will not take long - with $event
$event = json_decode($input);
$reference = $event->data->reference;
$email = $event->data->customer->email;
$eventMessage = $event->event;
file_put_contents("webhookApi.txt", PHP_EOL.$input, FILE_APPEND);
exit();
?>
`

Global variables values Node.js are missing on App Engine

I have a Node.js service deployed on App Engine which uses the Dialogflow fulfillment library. The scenario is this: I have an async function which retrieves the credentials using Secret manager and, with that info, calls an API that brings a url instance and a token back. This is a server-to-server authentication (OAuth), so it is the same for all users that access it. I set those values in global variables, like this:
let globalUser = "";
let globalPass = "";
...
async function credentials() {
const credentials = await secretsInstance.getCredentials();
const parsedCredentials = JSON.parse(credentials);
const user = parsedCredentials.user;
const pass = parsedCredentials.pass;
//setting the values to the global variables
globalUser = user;
globalPass = pass;
//call the authentication API - in the callback I set other global variables
await authApiInstance.authenticate(user, pass, callback);
}
After the callback function is called, I set the instance url and token to the global variables.
The token gets expired each 20 minutes, so I need to keep it updated. For that I call a setInterval function in which I call the authApiInstance.authenticate(...)
The problem here is that, when receiving a POST request coming from Dialogflow, I need to call another API that needs that url, which in this stage is empty for the first time, so it throws ECONNREFUSED. Then if I call the server other times, the variable is set.
The logs in GCP are like this:
2020-08-14 23:29:49.078 BRT
"Calling the loadQuestions API
2020-08-14 23:29:49.078 BRT
"The url is: /services/…
2020-08-14 23:29:49.091 BRT
"CATCH: Error: connect ECONNREFUSED 127.0.0.1:80"
2020-08-14 23:29:49.268 BRT
dialogflowGatewayProdxjmztxaet4d8Function execution took 764 ms, finished with status code:
200
2020-08-14 23:29:49.278 BRT
{ message_id: '39045207393', status: 200 }
2020-08-14 23:29:49.289 BRT
"Credentials ok"
2020-08-14 23:29:49.976 BRT
"Url set"
As it can be seen, the credentials and url were set after the API got called, so it didn't have a url to proceed successfully with the call.
I could call the function inside the POST, each time there is a request to guarantee that it will always exist, but the performance would be lost, especially dealing with Chatbots that must be quick.
I also tried the warmup approach, in which theoretically it would be called when deploying and changing the instance (but it could not be called, as by docs):
app.get('/_ah/warmup', (req, res) => {
credentials();
});
How could I approach this? I'm pretty new to Node.js and the server world.
Thanks
credentials(); by itself. no need to do it in express. The issue i would be race condition on the the shared credential.
crude example assuming the event loop has only these script in queue :
let say, you have 2 concurrent users A and B. A request and found the credential expire which in turn request new credential. B request before the credential return from A request, which in turn request another credential. Based on node eventloop, A then get credential_A , B will get credential B. If your third party only allow single credential then A will get an error from api call.
So the approach would be to forward the credential related task to one module, which manages the credential. background task or on request ( get token it expires on request) will face the same race problem. since node doesn't have context of thread, it is simple.
let credential = {}
let isUpdating = false;
const _updateCrediental = (newCrediential){
//map here
}
const _getCredential = async()=> {
try{
if(!updating){
updating = true;
const newCrediential = await apiCall();
updateCrediential(newCrediential);
updating = false;
return credential;
}else{
return false;
}
}catch(err){
throw err;
}
}
export.getCredential = ()=>{
if(credentialIsValid()){
return credential;
}
return __getCredential();
}
/// check the return if it promise type then waaait for it if its false then wait for certain time and check again.
An improvement to this would be using event to instead of using timeout.
I myself would prefer work with database as well as you might want to log credential generation as well. Most database promise certain kind of transaction or locking. (feel safer)

How to receive Shopify Webhook?

Below is my code.
define('SHOPIFY_APP_SECRET', 'xxxxxxxxxx');
function verify_webhook($data, $hmac_header)
{
$calculated_hmac = base64_encode(hash_hmac('sha256', $data, SHOPIFY_APP_SECRET, true));
return hash_equals($hmac_header, $calculated_hmac);
}
$hmac_header = $_SERVER['HTTP_X_SHOPIFY_HMAC_SHA256'];
$data = file_get_contents('php://input');
$verified = verify_webhook($data, $hmac_header);
echo "<pre>";
print_r($data);
exit;
?>
I've registered the app/uninstalled webhook.
So this is my code but not receiving any response
I know it is a late answer. But might helpful for the future user who will land here. You forgot to save the response you are getting from uninstall webhook to somewhere. Considered saving response to file. here is php code to save. After saving the response you can read or do processing after that.
file_put_contents($newFileName, $data);
Also, save the response only when HMAC hash matched you got from api. You can get domain name and for which topic api is fired. below is code. Do the necessary work.
$domain = $_SERVER['X-Shopify-Shop-Domain'];
$topic = $_SERVER['X-Shopify-Topic'];
Let me know if you are looking for more detail. thanks

How to properly use redis with servicestack in a multi-thread environment?

I assumed that we should use basicredisclientmanager or pooledredisclientmanager?
I tried this
private void dddddd()
{
for(int i=0;i<=1000;i++)
{
var client = new BasicRedisClientManager(new string[] { "host1", "host2", "host3" }).GetClient();
//do something with client
}
}
This loop runs fine for the first 100 plus but after that, I always got an error "Unknown Command Role"?? What is that and how to fix it? I need help!
I also tried to make a new class called MyRedisMgr and created a static property to create some sort of singleton but it didn't work either.
public BasicRedisClientManager MyMgr = new BasicRedisClientManager(new string[] { "host1", "host2", "host3" });
And then I use it like
for(int i=0;i<=1000;i++)
{
var client = MyRedisMgr.MyMgr.GetClient();
//do something with client
}
Please read the documentation on the proper usage of Redis Client Manager which should only be used as a singleton.
The BasicRedisClientManager doesn't have any connection pooling so every time you call GetClient() you're opening a new TCP connection with the redis-server. Unless you understand the implications you should be using one of the Pooled Redis Client Managers, e.g: RedisManagerPool.
You also need to always dispose the client after its used so that it can either be re-used or the TCP connection disposed of properly.
So your code sample should look like:
//Always use the same singleton instance of a Client Manager
var redisManager = new RedisManagerPool(masterHost);
for(int i=0;i<=1000;i++)
{
using (var redis = redisManager.GetClient())
{
//do something with client
}
}
The "Unknown Command Role" error is due to using an old version of Redis Server. The ROLE command was added in redis 2.8.12 but this API should only be used if your using redis-server v2.8.12+, so you shouldn't be getting this error by default. You can avoid this error by upgrading to either the stable v3.0 or old 2.8 versions of redis-server which has this command.
If you want to continue using an older version, use the INFO command to check what version you're running then tell ServiceStack.Redis what the version is with:
RedisConfig.AssumeServerVersion = 2600; //e.g. v2.6
RedisConfig.AssumeServerVersion = 2612; //e.g. v2.6.12

How to set timeout for IWbemLocator::ConnectServer?

Now I am writing a WMI query utility following the examples provided in this link:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa390422(v=vs.85).aspx
But I find that the program may blocking on the call to IWbemLocator::ConnectServer. Here is the code:
hres = pLoc->ConnectServer(
_bstr_t(L"\\\\COMPUTERNAME\\root\\cimv2"),
_bstr_t(useToken?NULL:pszName), // User name
_bstr_t(useToken?NULL:pszPwd), // User password
NULL, // Locale
NULL, // Security flags
_bstr_t(useNTLM?NULL:pszAuthority),// Authority
NULL, // Context object
&pSvc // IWbemServices proxy
);
My question is how can I set a time out option, before calling IWbemLocator::ConnectServer.
As per the ConnectServer method description, setting the lSecurityFlags parameter to WBEM_FLAG_CONNECT_USE_MAX_WAIT enforces a 2 minute timeout. Looks like there's no way to set a custom timeout though.

Resources