locked
How to make WinJS appendTextAsync wait until file not busy?

    Question

  • I have code like this for logging in my WinJS app:

    var log_file = null;
    
    function setupLogFile() {
        var logFn = function (message, tag, type) {
            if (!log_file) return; // log_file is global, setup below with a StorageFile object
            Windows.Storage.FileIO.appendTextAsync(log_file, tag + ' ' + type + ': ' + message)
                .done(null, function (error) {
                    // I have a breakpoint here to catch the error
                    var msg = error.detail.message;
                    }
                });
        };
    
        app_folder.createFolderAsync('logs', Windows.Storage.CreationCollisionOption.openIfExists)
           .then(function (logfolder) {
               var now = new Date();
               var logfilename = config.device + "_" + now.toDateString() + ".log";
               return logfolder.createFileAsync(logfilename, Windows.Storage.CreationCollisionOption.openIfExists)
           })
           .done(function (file) {
               log_file = file; // save in global var
               WinJS.Utilities.startLog({ tags: "myApp", action: logFn });
           });
    }
    
    setupLogFile();
    
    // ...
    // do stuff and log things
    // ...
    
    WinJS.log && WinJS.log('I did some stuff', 'myApp','info');
    WinJS.log && WinJS.log('I got an error: '+error, 'myApp','error');

    Intermittently, I get an error in my logFn "The process cannot access the file because it is in use by another process" or "Access is denied". I think that multiple calls to WinJS.log are colliding because of the async nature of the appendText call and trying to get a handle to the log file before the previous logging call is finished writing.

    Can I make appendTextAsync wait until the log file is not in use? I can't find any calls to check if the file is busy. I think there is a way to make appendTextAsync act in a synchronous way but I'd like to avoid doing that in all cases since this is just an intermittent case.

    Wednesday, September 17, 2014 2:47 PM

Answers

  • Found a solution with the help of good folks over at StackOverflow (@Bergi). Slight reorganization of the function to initially store the file creation promise in log_file, then after every log_fn call store the appendTextAsync promise back into log_file so everything gets queued up appropriately:

    function startLogFile() {
        if (log_file) { 
            WinJS.Utilities.stopLog();
            log_file.done(function (file) { /* close file handle somehow? */ });
            log_file = null;
        }
    
        log_file = app_folder.createFolderAsync('logs', Windows.Storage.CreationCollisionOption.openIfExists)
            .then(function (logfolder) {
                var now = new Date();
                var logfilename = config.device + "_" + now.toDateString() + ".log";
                return logfolder.createFileAsync(logfilename, Windows.Storage.CreationCollisionOption.openIfExists)
            });
    
        WinJS.Utilities.startLog({
            tags: "myApp",
            action: function log_fn(message, tag, type) {
                log_file = log_file.then(function (file) {
                    return Windows.Storage.FileIO.appendTextAsync(file, tag + ' ' + type + ': ' + message)
                        .then(function () {
                            return file;
                        }, function (error) {
                            // I have a breakpoint here to catch the error
                            var msg = error.detail.message;
                            return file; // for further logs, or
                            throw error; // go stop logging
                        });
                    });
                }
            });
        WinJS.log && WinJS.log("INITIALIZED LOG FILE", "myApp", "info");
    };
    

    • Marked as answer by amHammock Wednesday, September 17, 2014 6:08 PM
    Wednesday, September 17, 2014 6:06 PM

All replies

  • Found a solution with the help of good folks over at StackOverflow (@Bergi). Slight reorganization of the function to initially store the file creation promise in log_file, then after every log_fn call store the appendTextAsync promise back into log_file so everything gets queued up appropriately:

    function startLogFile() {
        if (log_file) { 
            WinJS.Utilities.stopLog();
            log_file.done(function (file) { /* close file handle somehow? */ });
            log_file = null;
        }
    
        log_file = app_folder.createFolderAsync('logs', Windows.Storage.CreationCollisionOption.openIfExists)
            .then(function (logfolder) {
                var now = new Date();
                var logfilename = config.device + "_" + now.toDateString() + ".log";
                return logfolder.createFileAsync(logfilename, Windows.Storage.CreationCollisionOption.openIfExists)
            });
    
        WinJS.Utilities.startLog({
            tags: "myApp",
            action: function log_fn(message, tag, type) {
                log_file = log_file.then(function (file) {
                    return Windows.Storage.FileIO.appendTextAsync(file, tag + ' ' + type + ': ' + message)
                        .then(function () {
                            return file;
                        }, function (error) {
                            // I have a breakpoint here to catch the error
                            var msg = error.detail.message;
                            return file; // for further logs, or
                            throw error; // go stop logging
                        });
                    });
                }
            });
        WinJS.log && WinJS.log("INITIALIZED LOG FILE", "myApp", "info");
    };
    

    • Marked as answer by amHammock Wednesday, September 17, 2014 6:08 PM
    Wednesday, September 17, 2014 6:06 PM
  • Nice to see the solution, should help other community members.

    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    Friday, September 19, 2014 1:51 AM
    Moderator