Я решил, что мне нужна в моем решении функция, которая возвращала бы промис, который разрешался, когда системное время было точным. Затем я мог бы вызвать эту функцию при запуске и использовать ее обратную связь, чтобы узнать, когда снова начать запись температуры. Для этого я решил использовать ntpClient, чтобы самостоятельно получить точное время и сравнить его с локальным системным временем. Когда они находятся в пределах желаемой точности, я могу выполнить обещание. Когда это не так, я устанавливаю таймер и перепроверяю время, продолжая до тех пор, пока местное системное время не станет достаточно точным. Итак, до сих пор это работало просто отлично после нескольких отключений электроэнергии (именно здесь изначально была обнаружена проблема с неточным временем).
Вот код, который я использовал:
const Promise = require('bluebird');
const ntpClient = Promise.promisifyAll(require('ntp-client'));
const log = require('./log');
function Decay(startT, maxT, decayAmount, decayTimes) {
// startT is initial delay (e.g. 5 seconds)
// maxT is the max delay this ever returns (e.g. 5 minutes)
// decayAmount is how much to decay when a threshold is crossed (e.g. increase by 0.5)
// decayTimes is how many invocations should trigger a decayAmount (e.g. every 5 times)
// example: var d = new Decay(5000, 5*60*1000, .5, 5);
// each 5 seconds, to a max of 5 minutes, getting 50% longer every 5 invocations
// make sure decayTimes is at least 1 and not negative
decayTimes = Math.max(decayTimes, 1);
var num = 0;
var currentDelay = startT;
var start = Date.now();
this.val = function() {
var elapsed = Date.now() - start;
// if evenly divisible by decayTimes, then bump the increment
if (num !== 0 && num % decayTimes === 0) {
currentDelay = Math.min(Math.round((1 + decayAmount) * currentDelay), maxT);
}
++num;
return currentDelay;
};
}
function checkSystemTime(precision) {
precision = precision || 5000;
return ntpClient.getNetworkTimeAsync("pool.ntp.org", 123).then(function(ntpTime) {
return Math.abs(ntpTime.getTime() - Date.now()) <= precision;
});
}
function waitForAccurateSystemTime(precision, howLong) {
var start = Date.now();
// retry starts every 5 seconds, repeats 5 times, then increases by 50%
// up until longest retry time of once every 15 minutes
var decay = new Decay(5000, 15*60*1000, .5, 5);
var errCntr = 0;
var inaccurateCntr = 0;
function logRetries() {
// only log anything if there were more than five consecutive errors
if (errCntr > 5 || inaccurateCntr > 0) {
log(7, "Time synchronization issue, errCntr = " + errCntr + ", inaccurateCntr = " + inaccurateCntr);
}
}
return new Promise(function(resolve, reject) {
function check() {
checkSystemTime(precision).then(function(accurate) {
if (accurate) {
resolve(true);
} else {
++inaccurateCntr;
again();
}
}, again);
}
function again() {
++errCntr;
if (errCntr == 10) {
// only log once here that we're in a retry loop on 10th retry
// final logging will be done later
log(7, "In retry loop waiting for system time to agree with ntp server time");
}
// if we're only supposed to go for a certain amount of time, then check to see
// if we exceeded that amount of time. If not, set timer for next decay() value.
if (!howLong || Date.now() - start <= howLong) {
setTimeout(check, decay.val());
} else {
var err = "timeout waiting for accurate system time";
log(7, err);
reject(err);
}
}
check();
}).then(function(result) {
logRetries();
return result;
}).catch(function(err) {
logRetries();
throw err;
});
}
module.exports = {
checkSystemTime: checkSystemTime,
waitForAccurateSystemTime: waitForAccurateSystemTime,
Decay: Decay
};
И я использую это так:
const validTime = require("./valid-time");
validTime.waitForAccurateSystemTime(2 * 60 * 1000, 0).then({
// start operation here that requires accurate system time
}).catch({
// abort process, no accurate system time could be found
});
.profile
читается каждой оболочкой входа в систему, .xxxrc
читается каждой интерактивной оболочкой после чтения .profile
.
Вы должны решить сами в зависимости от того, что вы хотите добавить.
Хорошая идея — поместить все, что устанавливает экспортированные переменные среды и, таким образом, распространяется на подоболочки, в.profile.
Вещи, которые не распространяются, должны быть в.bashrc или в любом другом файле, на который смотрит ваша оболочка. Это напр. определения псевдонимов и функций.
Bash имеет довольно сложную логику, определяющую, какие сценарии он запускает и когда.
Но в основном это сводится к:
ulimit
s ), вам обычно нужно устанавливать их только один раз при каждом входе в систему, так что это будет более эффективно поместить их в .profile
, а не в .bashrc
. PATH
с помощью конструкции, подобной PATH=$PATH:/some/directory
), затем помещение такого параметра в .bashrc
приведет к тому, что это добавление будет происходить во второй раз всякий раз, когда вы запускаете другой процесс оболочки, что было бы глупо и расточительно. Например, если вы установите PATH=$PATH:/some/directory
в .bashrc
, он отлично работает в вашей основной оболочке. Но когда вы запускаете редактор, а затем используете его функцию выхода из оболочки, вы можете обнаружить, что ваш PATH теперь имеет значение, подобное ...:/some/directory:/some/directory
. Каждый уровень дочерних оболочек будет добавлять каталог в PATH в другой раз. Наследуемые аддитивные настройки обычно лучше всего помещать в .profile
. .bashrc
. Если вы определили их в .profile
,вы можете найти их недоступными в оболочках, запущенных с использованием функции выхода из оболочки в различных приложениях. (Это также означает, что вы, вероятно, захотите добавить команду для получения вашего .bashrc
в конце вашего .profile
, чтобы основная оболочка входа в сеанс также получала эти определения, если только ваш дистрибутив не является стандартным /etc/profile
или по умолчанию .profile
уже обеспечивает эту функциональность.)С графическим интерфейсом пользователя связана еще одна сложность. Сеанс GUI обычно будет источником содержимого .profile
или его эквивалента при входе в систему (, поскольку соответствующий сценарий запуска сеанса -запускается как оболочка входа в систему ), поэтому любые наследуемые настройки, сделанные там, обычно наследуются среда рабочего стола и, в свою очередь, любое приложение, запускаемое с помощью значков или меню на рабочем столе.
Любые окна терминала в сеансе X11 GUI можно настроить одним из двух способов.:
.profile
или эквивалент. .bashrc
или эквивалент. Наследуемые параметры наследуются от основного сеанса входа в систему с графическим интерфейсом, через процессы среды рабочего стола/менеджера окон.