Search code examples
phpweb-servicesapicachingunlink

Files disappearing in the middle of a function


Interesting problem that I ran into today, so I'm writing this post for advice for how to deal with this now and in the future with other parts of my application (and maybe help someone else).

Consider this method:

protected function unlinkCachePath($cachePath) {
    if (!file_exists($cachePath)) {
        throw new \Exception("Invalid cache file path '$cachePath'");
    }
    if (!is_writable($cachePath)) {
        throw new \Exception("Check permissions for file path '$cachePath'");
    }
    $result = unlink($cachePath); // delete file
    if (!$result) {
        throw new \Exception("Problem deleting cache file '$cachePath'");
    }
    return true;
}

Pretty straightforward, right? Well, it turns out that the unlink() function was intermittently not working correctly. Which was odd, because I had a file_exists() check before attempting my unlink().

But still, it was generating a 'file not found' error. So I went out to debug, to find out what the heck was going on.

Debugging attempt:

protected function unlinkCachePath($cachePath) {

    // debug the cache path
    echo "testing cache path: $cachePath <br />";

    // check if the file exists
    $this->debugFileExists($cachePath,'1'); 

    if (!file_exists($cachePath)) {
       throw new \Exception("Invalid cache file path '$cachePath'");
    }

    // ...check again
    $this->debugFileExists($cachePath,'2'); 

    if (!is_writable($cachePath)) {
       throw new \Exception("Check permissions for file path '$cachePath'");
    }

    // ...and again
    $this->debugFileExists($cachePath,'3'); 

    $result = unlink($cachePath); // delete file

    // ...and again
    $this->debugFileExists($cachePath,'4');

    if (!$result) {
        throw new \Exception("Problem deleting cache file '$cachePath'");
    }
    return true;
}

private function debugFileExists($filePath, $attemptNumber) {
    if (file_exists($filePath)) {
        $response = "pass";
    } else { 
        $response = "fail";
    }
    echo "file_exists() test $attemptNumber: $response <br />";
}

Results:

testing cache path: /path/to/file.json
file_exists() test 1: pass
file_exists() test 2: pass
file_exists() test 3: fail
# unlink(file): No such file or directory
file_exists() test 4: fail

Wait, WHAT??

Here I am, scratching my head. How can the file exist, and then in the same function, suddenly not exist? Any insight on to what the heck could be happening?

Thank you.


Solution

  • Turns out, my application's API backend is PHP, while the frontend is angular. In rare cases, multiple frontend calls to an API, which hits unlinkCachePath($cachePath), would happen simultaneously -- and in the middle of a function, the file would delete! Because of this particular problem, the issue was not caught by extensive testing.