Laravel/Lumen MemcachedStore calculateExpiration method (memcached set with unixtimestamp) - php

In core I have aforementioned class (MemcachedStore), which has put method as:
$a = $this->memcached->set(
$this->prefix.$key, $value, $this->calculateExpiration($seconds)
);
Memcached's set method accepts three parameters: key, value, seconds_to_store_in_cache
My questions is: Why would I need to calculate expiration Carbon::now() + seconds passed to this function?
Result: This is not working. Memcached returns 0 "success". But entry is not written. (With "get" method I cant find it)
If I just pass seconds (override in core class), everything works as expected
UPD! Nothing to do with laravel or lumen

Actually Memchached's set method can accept third parameter as unixtimestamp, but in this case memcached time (os time) should be correct. Memcached time can be checked by Memchached's getStats

Related

Call artisan command from the same command

In the handle of your custom Laravel command, can you call the command again? Like this, described using sort of pseudo-code:
public function handle() {
code..
code..
$this->importantValue = $this->option('value'); //value is 'hello'
if(something) {
//call of the same command is made, but with different arguments or options
//command does stuff and ends successfully
$this->call('myself' [
'value' => 'ahoy'
];
//I expect the handle to be returned to the original command
}
var_dump($this->importantValue); //this equals 'ahoy'
}
Why is this? What does that newly called command has in common with the original within which it had been called?
EDIT: The newly called command would not reach the condition something it would not call itself again (forever). The original command seems to pick up from where it left (before calling itself the first and only time) yet it seems it has had inherited the "children's" variables.
I do think that calling Artisan::call() instead of $this->call() might avoid that problem (note that avoiding is not the same as solving)...
#t-maxx: I'm getting the exact same issue and I'm not sure that #ben understands.
I have a command that is recursive, based on an argument, depth. The depth argument is set to a protected property as one of the first steps in handle(). Then, if depth is greater than zero, it calls itself (via $this->call()), but passing $this->depth - 1. I watch each successive call and it just goes down and down and down, never plateauing or bouncing up was the recursion would allow and as one would expect.
So...while I'm not 100% sure what's going on, I'm thinking of getting the depth option once, but passing it around as a variable (versus a property on the object). This is ugly, I think, but it may be the only solution until this is recognized and resolved. On the other hand, it could be that we're both doing the wrong thing.
Calling Artisan::call() for me leads to other issues that I'd rather avoid. The command I'm working with writes to a file and I don't want a bunch of separate commands competing for the same file.
Yes, you can Programmatically Executing Commands using Artisan::call
Artisan::call('myself', [
'value' => 'ahoy'
]);

Laravel Event - fails with class does not have a method

Using Laravel 5.5, I have a listener called JobEventSubscriber that is using a database queue. It has a method called uploadFileToPartner that is triggered whenever a JobFilesUploaded event is fired.
Here is the code of my subscribe method:
public function subscribe($events){
$events->listen(JobSaved::class, JobEventSubscriber::class . '#syncToCrm');
$events->listen(JobFilesUploaded::class, JobEventSubscriber::class . '#uploadFileToPartner');
}
Whenever either of these events fire, the database Listener fails with the following error:
ErrorException: call_user_func_array() expects parameter 1 to be a valid callback,
class 'App\Listeners\JobEventSubscriber' does not have a method 'uploadFileToPartner'
in /var/www/html/vendor/laravel/framework/src/Illuminate/Events/CallQueuedListener.php:79
When I change my queue_driver to sync it works. I also went into Tinker and typed:
>>> use App\Listeners\JobEventSubscriber
>>> $eventSubscriber = app(JobEventSubscriber::class);
=> App\Listeners\JobEventSubscriber {#879
+connection: "database",
}
>>> method_exists($eventSubscriber, 'uploadFileToPartner');
=> true
What is wrong here where it cannot find methods that are definitely there.
It may be relevant to mention that I recently updated this app from Larvel 5.4.
Upon reading the docs it says that if you change your code you need to restart your queue process.
Specifically it says:
Remember, queue workers are long-lived processes and store the booted application state in memory. As a result, they will not notice changes in your code base after they have been started. So, during your deployment process, be sure to restart your queue workers.
I changed the name of the methods, and then I didn't restart the queue. So the queue was receiving events with the new names but it was executing old code. As a result the method names weren't recognized.

How to properly use PHP5 semaphores?

I have this function that tries to read some values from cache. But if value does not exists it should call alternative source API and save new value into the cache. However, server is very overloaded and almost each time when value does not exists more then one requests are created (a lot of API calls) and each of them will store new vale into cache. However, what I want is to be able to call API many times, but only one process/request to be able to store it in cache:
function fetch_cache($key, $alternativeSource) {
$redis = new Redis();
$redis->pconnect(ENV_REDIS_HOST);
$value = $redis->get($key);
if( $value === NULL ) {
$value = file_get_contents($alternativeSource);
// here goes part that I need help with
$semaphore = sem_get(6000, 1); // does this need to be called each time this function is called?
if( $semaphore === FALSE ) {
// This means I have failed to create semaphore?
}
if( sem_aquire($semaphore, true) ) {
// we have aquired semaphore so here
$redis->set($key, $value);
sem_release($semaphore); // releasing lock
}
// This must be call because I have called sem_get()?
sem_remove($semaphore);
}
return $value;
}
Is this proper use of semaphore in PHP5?
Short answer
You don't need to create and remove semaphores within the fetch_cache function. Put sem_get() into an initialization method (such as __construct).
You should remove semaphores with sem_remove(), but in a cleanup method (such as __destruct). Or, you might want to keep them even longer - depends on the logic of your application.
Use sem_acquire() to acquire locks, and sem_release() to release them.
Description
sem_get()
Creates a set of three semaphores.
The underlying C function semget is not atomic. There is a possibility of race condition when two processes trying to call semget. Therefore, semget should be called in some initialization process. The PHP extension overcomes this issue by means of three semaphores:
Semaphore 0 a.k.a. SYSVSEM_SEM
Is initialized to sem_get's $max_acquire and decremented as processes acquires it.
The first process that called sem_get fetches the value of SYSVSEM_USAGEsemaphore (see below). For the first process, it equals to 1, because the extension sets it to 1 with atomic semop function right after semget. And if this is really the first process, the extension assigns SYSVSEM_SEM semaphore value to $max_acquire.
Semaphore 1 a.k.a. SYSVSEM_USAGE
The number of processes using the semaphore.
Semaphore 2 a.k.a. SYSVSEM_SETVAL
Plays a role of a lock for internal SETVAL and GETVAL operations (see man 2 semctl). For example, it is set to 1 while the extension sets SYSVSEM_SEM to $max_acquire, then is reset back to zero.
Finally, sem_get wraps a structure (containing the semaphore set ID, key and other information) into a PHP resource and returns it.
So you should call it in some initialization process, when you're only preparing to work with semaphores.
sem_acquire()
This is where the $max_acquire goes into play.
SYSVSEM_SEM's value (let's call it semval) is initially equal to $max_acquire. semop() blocks until semval becomes greater than or equal to 1. Then 1 is substracted from semval.
If $max_acquire = 1, then semval becomes zero after the first call, and the next calls to sem_acquire() will block until semval is restored by sem_release() call.
Call it when you need to acquire the next "lock" from the available set ($max_acquire).
sem_release()
Does pretty much the same as sem_acquire(), except it increments SYSVSEM_SEM's value.
Call it when you need to no longer need the "lock" acquired previously with sem_acquire().
sem_remove()
Immediately removes the semaphore set, awakening allprocesses blocked in semop on the set (from IPC_RMID section, SEMCTL(2) man page).
So this is effectively the same as removing a semaphore with ipcrm command.
The file permissions should be 0666 instead of 6000 for what you're trying to do.

Laravel 5 > Using monolog introspection processor

I have configured Laravel 5 to use a custom logging configuration (default is way too simple). I've added monolog's IntrospectionProcessor to log the file name and line number of the log call.
The problem is that all lines get the same file and line number:
[2015-06-29 17:31:46] local.DEBUG (/home/vagrant/project/vendor/laravel/framework/src/Illuminate/Log/Writer.php#201): Loading view... [192.168.10.1 - GET /loans/create]
Is there a way to config the IntrospectionProcessor to print the actual lines and not the facade ones?
If I do Log::getMonolog()->info('Hello'); it works and prints the correct file and line number... but I don't know how safe is to avoid calling the Writer.writeLog function because it fires a log event (is it safe to not fire that event?).
(Only tried in Laravel 4.2!)
When pushing the Introspection Processor to Monolog it is possible to give an skipClassesPartial array as second parameter in the IntrospectionProcessor contructor. With this array it is possible to skip the Laravel Illuminate classes and the logger logs the class calling the log method.
$log->pushProcessor(new IntrospectionProcessor(Logger::DEBUG, array('Illuminate\\')));
also see: https://github.com/Seldaek/monolog/blob/master/src/Monolog/Processor/IntrospectionProcessor.php
I know this is an old question but I thought I'd give a quick update because it's pretty easy to get this done now.
I haven't tried with Laravel but My own logging mechanism is within a LoggingService wrapper class. As such the introspection was only giving details about the service rather than the caller.
after reading Matt Topolski's answer, I had a look in the IntrospectionProcessor.php. the constructor looks like this:
__construct($level = Logger::DEBUG, array $skipClassesPartials = array(), $skipStackFramesCount = 0)
All I had to do was add the processor like this:
log->pushProcessor(new IntrospectionProcessor(Logger::DEBUG, array(), 1));
This is actually the expected functionality unless you're having the handler process the logs directly (check out the comments at the top of IntrospectionProcessor.php). My guess is you have a wrapper function around the logger and you're calling it from Writer.php -- BUT
If you look at the code for IntrospectionProcessor.php you'll see a bit of code on lines 81 to 87 that decides how to format that stack trace, and it still has access to the stack. If you bump the $i values for $trace[$i - 1] / $trace[$i] up one (aka $trace[$i]/$trace[$i + 1] respectively) you can 'climb' the stack back to where you want.
It's important to note that the 'class' and 'function' parts of the trace need to be one level of the stack higher than the 'file' and 'line.'
On a personal (plz dont mod me bruhs) note, I'd like to see functionality to include a stack offset when throwing the log in. I know what function I want to blame if an error shoots out when I write the error_log('ut oh') but I might(will) forget that by the time the 'ut oh' comes.

Can I "Mock" time in PHPUnit?

... not knowing if 'mock' is the right word.
Anyway, I have an inherited code-base that I'm trying to write some tests for that are time-based. Trying not to be too vague, the code is related to looking at the history of an item and determining if that item has now based a time threshold.
At some point I also need to test adding something to that history and checking that the threshold is now changed (and, obviously, correct).
The problem that I'm hitting is that part of the code I'm testing is using calls to time() and so I'm finding it really hard to know exactly what the threshold time should be, based on the fact that I'm not quite sure exactly when that time() function is going to be called.
So my question is basically this: is there some way for me to 'override' the time() call, or somehow 'mock out' the time, such that my tests are working in a 'known time'?
Or do I just have to accept the fact that I'm going to have to do something in the code that I'm testing, to somehow allow me to force it to use a particular time if need be?
Either way, are there any 'common practices' for developing time-sensitive functionality that is test friendly?
Edit:
Part of my problem, too, is the fact that the time that things occurred in history affect the threshold. Here's an example of part of my problem...
Imagine you have a banana and you're trying to work out when it needs to be eaten by. Let's say that it will expire within 3 days, unless it was sprayed with some chemical, in which case we add 4 days to the expiry, from the time the spray was applied. Then, we can add another 3 months to it by freezing it, but if it's been frozen then we only have 1 day to use it after it thaws.
All of these rules are dictated by historical timings. I agree that I could use the Dominik's suggestion of testing within a few seconds, but what of my historical data? Should I just 'create' that on the fly?
As you may or may not be able to tell, I'm still trying to get a hang of all of this 'testing' concept ;)
I recently came up with another solution that is great if you are using PHP 5.3 namespaces. You can implement a new time() function inside your current namespace and create a shared resource where you set the return value in your tests. Then any unqualified call to time() will use your new function.
For further reading I described it in detail in my blog
Carbon::setTestNow(Carbon $time = null) makes any call to Carbon::now() or new Carbon('now') return the same time.
https://medium.com/#stefanledin/mock-date-and-time-with-carbon-8a9f72cb843d
Example:
public function testSomething()
{
$now = Carbon::now();
// Mock Carbon::now() / new Carbon('now') to always return the same time
Carbon::setTestNow($now);
// Do the time sensitive test:
$this->retroEncabulator('prefabulate')
->assertJsonFragment(['whenDidThisHappen' => $now->timestamp])
// Release the Carbon::now() mock
Carbon::setTestNow();
}
The $this->retroEncabulator() function needs to use Carbon::now() or new Carbon('now') internally of course.
For those of you working with symfony (>= 2.8): Symfony's PHPUnit Bridge includes a ClockMock feature that overrides the built-in methods time, microtime, sleep and usleep.
See: http://symfony.com/doc/2.8/components/phpunit_bridge.html#clock-mocking
You can mock time for test using Clock from ouzo-goodies. (Disclaimer: I wrote this library.)
In code use simply:
$time = Clock::now();
Then in tests:
Clock::freeze('2014-01-07 12:34');
$result = Class::getCurrDate();
$this->assertEquals('2014-01-07', $result);
I had to simulate a particular request in future and past date in the app itself (not in Unit Tests). Hence all calls to \DateTime::now() should return the date that was previously set throughout the app.
I decided to go with this library https://github.com/rezzza/TimeTraveler, since I can mock the dates without altering all the codes.
\Rezzza\TimeTraveler::enable();
\Rezzza\TimeTraveler::moveTo('2011-06-10 11:00:00');
var_dump(new \DateTime()); // 2011-06-10 11:00:00
var_dump(new \DateTime('+2 hours')); // 2011-06-10 13:00:00
Personally, I keep using time() in the tested functions/methods. In your test code, just make sure to not test for equality with time(), but simply for a time difference of less than 1 or 2 (depending on how much time the function takes to execute)
You can overide php's time() function using the runkit extension. Make sure you set runkit.internal_overide to On
Using [runkit][1] extension:
define('MOCK_DATE', '2014-01-08');
define('MOCK_TIME', '17:30:00');
define('MOCK_DATETIME', MOCK_DATE.' '.MOCK_TIME);
private function mockDate()
{
runkit_function_rename('date', 'date_real');
runkit_function_add('date','$format="Y-m-d H:i:s", $timestamp=NULL', '$ts = $timestamp ? $timestamp : strtotime(MOCK_DATETIME); return date_real($format, $ts);');
}
private function unmockDate()
{
runkit_function_remove('date');
runkit_function_rename('date_real', 'date');
}
You can even test the mock like this:
public function testMockDate()
{
$this->mockDate();
$this->assertEquals(MOCK_DATE, date('Y-m-d'));
$this->assertEquals(MOCK_TIME, date('H:i:s'));
$this->assertEquals(MOCK_DATETIME, date());
$this->unmockDate();
}
In most cases this will do. It has some advantages:
you don't have to mock anything
you don't need external plugins
you can use any time function, not only time() but DateTime objects as well
you don't need to use namespaces.
It's using phpunit, but you can addapt it to any other testing framework, you just need function that works like assertContains() from phpunit.
1) Add below function to your test class or bootstrap. Default tolerance for time is 2 secs. You can change it by passing 3rd argument to assertTimeEquals or modify function args.
private function assertTimeEquals($testedTime, $shouldBeTime, $timeTolerance = 2)
{
$toleranceRange = range($shouldBeTime, $shouldBeTime+$timeTolerance);
return $this->assertContains($testedTime, $toleranceRange);
}
2) Testing example:
public function testGetLastLogDateInSecondsAgo()
{
// given
$date = new DateTime();
$date->modify('-189 seconds');
// when
$this->setLastLogDate($date);
// then
$this->assertTimeEquals(189, $this->userData->getLastLogDateInSecondsAgo());
}
assertTimeEquals() will check if array of (189, 190, 191) contains 189.
This test should be passed for correct working function IF executing test function takes less then 2 seconds.
It's not perfect and super-accurate, but it's very simple and in many cases it's enough to test what you want to test.
Simplest solution would be to override PHP time() function and replace it with your own version. However, you cannot replace built-in PHP functions easily (see here).
Short of that, the only way is to abstract time() call to some class/function of your own that would return the time you need for testing.
Alternatively, you could run the test system (operating system) in a virtual machine and change the time of the entire virtual computer.
Here's an addition to fab's post. I did the namespace based override using an eval. This way, I can just run it for tests and not the rest of my code. I run a function similar to:
function timeOverrides($namespaces = array()) {
$returnTime = time();
foreach ($namespaces as $namespace) {
eval("namespace $namespace; function time() { return $returnTime; }");
}
}
then pass in timeOverrides(array(...)) in the test setup so that my tests only have to keep track of what namespaces time() is called in.
Disclaimer: I wrote this library.
If you are free to install php extensions in your system, you could then use https://github.com/slope-it/clock-mock.
That library requires ext-uopz >= 6.1.1 and by using ClockMock::freeze and ClockMock::reset you can move the internal php clock to whatever date and time you like. The cool thing about it is that it requires zero modifications to your production code because it mocks transparently \DateTime and \DateTimeImmutable objects as well as some of the global functions (e.g. date(), time(), etc...).
You can use libfaketime
https://github.com/wolfcw/libfaketime
LD_PRELOAD=src/libfaketime.so.1 FAKETIME="#2020-01-01 11:12:13" phpunit
It will be as if you changed your system clock but only for that process, and it will work regardless of how low level your phpcode is
(Except if they use an external API call to get the time of course !)

Categories