- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我是 Node/Express 的新手,我正在做一个预约系统。我希望我的用户在他们想要的那一天进行预约,我的系统会在那个确切的时间向他们发送通知。我发现“node-schedule”模块非常适合这个任务,但我不知道在哪里实现它。无论如何将所有任务存储在我的 app.js 中,或者每次我达到某个终点时只创建一个 Node 计划任务是否足够,例如:
router.get('/', function(req, res, next) {
var j = schedule.scheduleJob(date, function(){
send notification();
});
res.send(200);
}
注意:我不想在我的 sql 表上运行常量 for 循环来检查日期
最佳答案
您需要通过使用 SQLite 之类的方式写入本地文件,将您的应用程序数据保存到某种形式的永久存储中。 ,运行您自己的数据库服务器(如 MongoDB )或使用基于云的存储服务,如 Amazon SimpleDb .
这些选项(以及许多其他选项)中的每一个都有 npm 模块,您可以使用它们来读取/写入/删除持久数据。有关示例,请参阅 MongoDb , SQLite3 , 和 SimpleDb ,所有这些都可以在 npmjs.com 上使用 npm
.
根据您在下面的评论:好吧,您确实询问了可以在哪里存储已安排的事件。 ;)
要保留所有计划的事件,使其在可能的服务器故障中幸存下来,您需要创建一个可存储的数据结构来表示它们,并为每个事件创建一个新的表示实例并将其存储到持久存储 (MySQL) .
通常,您会使用以下内容:
{
when:DateTime -- timestamp when the event should fire
what:Action -- what this event should do
args:Arguments -- arguments to pass to Action
pending:Boolean=true -- if false, this event has already fired
}
当您初始化您的服务器时,您将查询您的持久存储以查找所有 pending===true
的事件,并使用结果初始化 node-schedule
的实例模块。
当您需要在服务器运行时安排一个新事件时,您需要创建一个新的事件表示,将其写入持久存储并使用它创建一个新的 node-schedule
实例。
最后,也是最重要的是为了让客户满意,当计划的事件成功完成时,就在您的事件处理程序(上面提到的 Action
)完成之前,它需要将它正在处理的事件的持久版本标记为 pending:false
,这样您就不会多次触发任何事件。
例如:
'use strict';
var scheduler = require('node-schedule');
/**
* Storable Representation of a Scheduled Event
*
* @param {string|Date} when
* @param {string} what
* @param {array.<string>} [args=[]]
* @param {boolean} [pending=true]
*
* @property {Date} PersistentEvent.when - the datetime this event should fire.
* @property {string} PersistentEvent.what - the name of the action to run (must match key of PersistentEvent.Actions)
* @property {array} PersistentEvent.args - args to pass to action event handler.
* @property {boolean} PersistentEvent.pending - if true, this event has not yet fired.
*
* @constructor
*
* @example
*
* var PersistentEvent = require('PersistentEvent'),
* mysql = require('mysql'),
* conn = mysql.createConnection({ ... });
*
* conn.connect();
*
* // at some point when initializing your app...
*
* // assign your persistent storage connection...
* PersistentEvent.setStore(conn);
*
* // load all pending event from persistent storage...
* PersistentEvent.loadAll$(function (err) {
* if (err) {
* throw new Error('failed to load all PersistentEvents: ' + err);
* }
*
* // from this point on, all persistent events are loaded and running.
*
* });
*/
var PersistentEvent = function (when, what, args, pending) {
// initialize
PersistentEvent.Cache.push(this.init({
when: when,
what: what,
args: args,
pending: pending
}));
};
// ==== PersistentEvent Static Methods ====
/**
* Pre-defined action event handlers.
* <p>
* Where the property key will be used to match the PersistentEvent.what property,
* and the property value is a event handler function that accepts an optional
* array of args and a callback (provided by PersistentEvent.prototype.schedule)
* </p>
*
* @property {object}
* @property {function} Actions.doSomething
* @property {function} Actions.doSomethingElse
*
* @static
*/
PersistentEvent.Actions = {
doSomething: function (args, cb) {
// defaults
args = args || [];
// TODO check specific args here ...
var result = true,
err = null;
// do your action here, possibly with passed args
cb(err, result);
},
doSomethingElse: function (args, cb) {
// defaults
args = args || [];
// TODO check specific args here ...
var result = true,
err = null;
// do your action here, possibly with passed args
cb(err, result);
}
};
/**
* Cache of all PersistentEvents
*
* @type {Array.<PersistentEvent>}
* @static
*/
PersistentEvent.Cache = [];
// Data Management
/**
* Connection to persistent storage.
* TODO - This should be abstracted to handle other engines that MySQL.
* @property {object}
* @static
*/
PersistentEvent.StorageConnection = null;
/**
* Sets the storage connection used to persist events.
*
* @param {object} storageConnection
* @static
*/
PersistentEvent.setStore = function (storageConnection) { // set the persistent storage connection
// TODO - check args here...
// Note: this function isn't really needed unless you're using other kinds of storage engines
// where you'd want to test what engine was used and mutate this interface accordingly.
PersistentEvent.StorageConnection = storageConnection;
};
/**
* Saves a PersistentEvent to StorageConnection.
*
* @param {PersistentEvent} event - event to save
* @param {function} cb - callback on complete
* @static
*/
PersistentEvent.save$ = function (event, cb) {
var conn = PersistentEvent.StorageConnection;
if (null === conn) {
throw new Error('requires a StorageConnection');
}
// TODO - check for active connection here...
// TODO - check args here...
conn.query('INSERT INTO TABLE when = :when, what = :what, args = :args, pending = :pending', event, cb);
};
/**
* Loads all PersistentEvents from StorageConnection.
* @param {function} cb -- callback on complete
* @static
*/
PersistentEvent.loadAll$ = function (cb) {
var conn = PersistentEvent.StorageConnection;
if (null === conn) {
throw new Error('requires a StorageConnection');
}
// check for active connection here...
// check args here...
conn.query('QUERY * FROM TABLE WHERE pending = true', function (err, results) {
if (err) {
return cb(err);
}
results.forEach(function (result) {
// TODO: check for existence of required fields here...
var event = new PersistentEvent(result.when, result.what, result.args, true);
event.schedule();
});
cb(null);
});
};
// ==== PersistentEvent Methods ====
/**
* Initialize an instance of PersistentEvent.
*
* @param {object} opts
* @return {PersistentEvent}
*/
Event.prototype.init = function (opts) {
// check args
if ('object' !== typeof opts) {
throw new Error('opts must be an object');
}
// set defaults
opts.args = opts.args || [];
opts.pending = opts.pending || true;
// convert string to Date, if required
if ('string' === typeof opts.when) {
opts.when = new Date(opts.when);
}
// check that opts contains needed properties
if (!opts.when instanceof Date) {
throw new Error('when must be a string representation of a Date or a Date object');
}
if ('string' !== typeof opts.what) {
throw new Error('what must be a string containing an action name');
}
if (!Array.isArray(opts.args)) {
throw new Error('args must be an array');
}
if ('boolean' !== typeof opts.pending) {
throw new Error('pending must be a boolean');
}
// set our properties
var self = this;
Object.keys(opts).forEach(function (key) {
if (opts.hasOwnProperty(key)) {
self = opts[key];
}
});
return this;
};
/**
* Override for Object.toString()
* @returns {string}
*/
PersistentEvent.prototype.toString = function () {
return JSON.stringify(this);
};
/**
* Schedule the event to run.<br/>
* <em>Side-effect: saves event to persistent storage.</em>
*/
PersistentEvent.prototype.schedule = function () {
var self = this,
handler = Actions[this.what];
if ('function' !== typeof handler) {
throw new Error('no handler found for action:' + this.what);
}
PersistentEvent.save$(self, function () {
self._event = scheduler.scheduleJob(self.when, function () {
handler(self.args, function (err, result) {
if (err) {
console.error('event ' + self + ' failed:' + err);
}
self.setComplete();
});
});
});
};
/**
* Sets this event complete.<br/>
* <em>Side-effect: saves event to persistent storage.</em>
*/
PersistentEvent.prototype.setComplete = function () {
var self = this;
delete this._event;
this.pending = false;
PersistentEvent.save$(this, function (err) {
if (err) {
console.error('failed to save event ' + self + ' :' + err);
}
});
};
请注意,这是一个首次通过的样板文件,向您展示了一种设计问题解决方案的方法。它将需要您进一步努力才能运行。
关于node.js - 在哪里存储我的 Node 计划,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30631388/
我正在学习构建单页应用程序 (SPA) 所需的所有技术。总而言之,我想将我的应用程序实现为单独的层,其中前端仅使用 API Web 服务(json 通过 socket.io)与后端通信。前端基本上是
当我看到存储在我的数据库中的日期时。 这是 正常 。日期和时间就是这样。 但是当我运行 get 请求来获取数据时。 此格式与存储在数据库 中的格式不同。为什么会发生这种情况? 最佳答案 我认为您可以将
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我正在尝试使用backbone.js 实现一些代码 和 hogan.js (http://twitter.github.com/hogan.js/) Hogan.js was developed ag
我正在使用 Backbone.js、Node.js 和 Express.js 制作一个 Web 应用程序,并且想要添加用户功能(登录、注销、配置文件、显示内容与该用户相关)。我打算使用 Passpor
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 8 年前。 Improve this ques
我尝试在 NodeJS 中加载数据,然后将其传递给 ExpressJS 以在浏览器中呈现 d3 图表。 我知道我可以通过这种方式加载数据 - https://github.com/mbostock/q
在 node.js 中,我似乎遇到了相同的 3 个文件名来描述应用程序的主要入口点: 使用 express-generator 包时,会创建一个 app.js 文件作为生成应用的主要入口点。 通过 n
最近,我有机会观看了 john papa 关于构建单页应用程序的精彩类(class)。我会喜欢的。它涉及服务器端和客户端应用程序的方方面面。 我更喜欢客户端。在他的实现过程中,papa先生在客户端有类
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我是一个图形新手,需要帮助了解各种 javascript 2D 库的功能。 . . 我从 Pixi.js 中得到了什么,而我没有从 Konva 等基于 Canvas 的库中得到什么? 我从 Konva
我正在尝试将一些 LESS 代码(通过 ember-cli-less)构建到 CSS 文件中。 1) https://almsaeedstudio.com/ AdminLTE LESS 文件2) Bo
尝试查看 Express Passport 中所有登录用户的所有 session ,并希望能够查看当前登录的用户。最好和最快的方法是什么? 我在想也许我可以在登录时执行此操作并将用户模型数据库“在线”
我有一个 React 应用程序,但我需要在组件加载完成后运行一些客户端 js。一旦渲染函数完成并加载,运行与 DOM 交互的 js 的最佳方式是什么,例如 $('div').mixItUp() 。对
请告诉我如何使用bodyparser.raw()将文件上传到express.js服务器 客户端 // ... onFilePicked(file) { const url = 'upload/a
我正在尝试从 Grunt 迁移到 Gulp。这个项目在 Grunt 下运行得很好,所以我一定是在 Gulp 中做错了什么。 除脚本外,所有其他任务均有效。我现在厌倦了添加和注释部分。 我不断收到与意外
我正在尝试更改我的网站名称。找不到可以设置标题或应用程序名称的位置。 最佳答案 您可以在 config/ 目录中创建任何文件,例如 config/app.js 包含如下内容: module.expor
经过多年的服务器端 PHP/MySQL 开发,我正在尝试探索用于构建现代 Web 应用程序的新技术。 我正在尝试对所有 JavaScript 内容进行排序,如果我理解得很好,一个有效的解决方案可以是服
我是 Nodejs 的新手。我在 route 目录中有一个 app.js 和一个 index.js。我有一个 app.use(multer....)。我还定义了 app.post('filter-re
我正在使用 angular-seed用于构建我的应用程序的模板。最初,我将所有 JavaScript 代码放入一个文件 main.js。该文件包含我的模块声明、 Controller 、指令、过滤器和
我是一名优秀的程序员,十分优秀!