您当前的位置: 首页 > 

寒冰屋

暂无认证

  • 1浏览

    0关注

    2286博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

AWS Lambda中的Cron表达式解析器

寒冰屋 发布时间:2022-03-15 20:59:08 ,浏览量:1

目录

介绍

解释代码

解析函数

特别案例

AWS设置

AWS Lambda

AWS API网关

AWS Amplify

  • 下载 index.html - 884 B​​​​​​​
  • 下载 index.js.txt - 3.1 KB
介绍

这个项目对我来说有点锻炼。我最近开始在AWS中学习初学者的东西,所以我想通过创建一个简单的API来测试Lambda函数。本文介绍了如何使用AWS Lambda(一个使用AWS Amplify的简单网站)创建API函数,并使用AWS API Gateway连接这两者。

lambda函数本身是一个用Node.js编写的cron表达式解析器。它将Cron表达式作为参数,并在该cron表达式下一次触发事件时计算并返回。

解释代码

通过API事件接收的表达式首先针对两个表达式进行测试,如果匹配,则将其拆分为要解析的数组。

var matches_POSIX = regex_POSIX.exec(testexp);
var matches_EXT = regex_EXT.exec(testexp);
var arr = [];
if(matches_POSIX === null && matches_EXT === null) {
    console.log("Expression does not match!!!");
    return null;
}
else if(matches_POSIX !== null) {
    console.log("Expression is POSIX");
    arr.push("*");
    matches_POSIX.forEach((m, i) => i != 0 ? arr.push(m) : null);
    arr.push("*");
    if(arr[3] != "?" && arr[5] == "*") arr[5] = "?";
    if(arr[5] != "?" && arr[3] == "*") arr[3] = "?";
}
else {
    console.log("Expression is EXTENDED");
    matches_EXT.forEach((m, i) => i != 0 ? arr.push(m) : null);
}

主要功能是getNextTime。它将遍历数组的所有元素并使用适当的参数调用resolve函数。它还将测试已解决的错误值,这基本上是返回数组的第一个元素中的值-1。

解析顺序为:年-月-星期-日-时-分-秒。这种倒推方法的原因是因为,例如,要知道一个月有多少天,我们需要知道它是哪一年,要知道某个日期的哪个工作日,我们需要知道月份和年份等。

稍后我们在确定下一个触发cron事件的时间时也会使用这种方法,因为我们希望通过获取最接近的未来日期来缩小时间窗口;这将在后面的文本中更彻底地解释。

解析函数

根据正在求值的cron表达式的哪一部分(通过第二个参数传递),这个函数被分成几个部分;参数值的含义在上面的注释中解释了:

switch(i) {
    // year
    case 6:
        if(m === "*") return Array.apply(null, Array(10)).map(function(e, i)
            { return ts.getFullYear() + i; }); // current and next 9 years
        if(!m.includes("-") && !m.includes(","))
             return [parseInt(m, 10)];         // single value
        return resolveList(m, i);              // list of years
    // month
    case 4:
        if(m === "*") return Array.apply(null,
            Array(12)).map(function(e, i) { return i; }); // return all months
        if(!m.includes("-") && !m.includes(",") && !isNaN(parseInt(m, 10)))
            return [parseInt(m, 10)-1];                   // single value numeric
        if(isNaN(parseInt(m, 10)) && month2num(m) != -1)
            return [month2num(m)-1];                      // single value string
        return resolveList(m, i).map(function(e,i)
            { return (e > 0 ? e-1 : e) }); // list of months
    // day of month
    case 3:
        if(m === "?") return undefined; // empty - use dw instead
        if(m === "*") return Array.apply(null, Array
            (new Date(yyyy, mm+1, 0).getDate())).map(function(e, i)
            { return i + 1; });         // return all days
        if(m.replace(/L|W/g,"").length != m.length)
            return null;                // last (week)day of month - skip,
                                        // resolve outside this function
        if(!m.includes("-") && !m.includes(","))
           return [parseInt(m, 10)];    // single value
        return resolveList(m, i);       // list of days
    // day of week
    case 5:
        if(m.replace(/L|#/g,"").length != m.length)
           return null;                    // just ignore special cases,
                                           // to be resolved outside this function
        if(m === "?") return undefined;    // empty - use dd instead
        if(m === "*") return Array.apply(null, Array(7)).map
           (function(e, i) { return i; }); // return all days
        if(!m.includes("-") && !m.includes(","))
           return [parseInt(m, 10)];       // single value numeric
        if(isNaN(parseInt(m, 10)) && day2num(m) != -1)
           return [day2num(m)];            // single value string
        return resolveList(m, i);          // list of days
    // hour
    case 2:
        if(m === "*") return Array.apply(null,
            Array(24)).map(function(e, i) { return i; }); // return all hours
        if(!m.includes("-") && !m.includes(",") && !m.includes("/"))
            return [parseInt(m, 10)];      // single value
        return resolveList(m, i);          // list of hours
    // min / sec
    case 1: case 0:
        if(m === "*") return Array.apply(null, Array(60)).map(function(e, i)
            { return i; });                // return all min/sec
        if(!m.includes("-") && !m.includes(",") && !m.includes("/"))
            return [parseInt(m, 10 )];     // single value
        return resolveList(m, i);          // list of min/sec
}

该resolve函数尝试为cron的每个部分返回一个包含所有可能值的数组(年份除外;因为年份是无限的,该函数最多将返回未来10年)。

如果提供了星号(*),则表示所有的值都是可能的,因此首先使用Array.apply函数创建一个数组,以null元素为初始值,然后使用map函数设置元素,例如12个月:

if(m === "*") return Array.apply(null, Array(12)).map(function(e, i) 
              { return i; }); // return all months

可能的结果要么是所有值(*),只有一个值,要么是用逗号分隔的列表或范围表示的值列表——这在名为resolveList的单独函数中解析:

function resolveList(m, i) {
        var retValue = [];
        var msplit;
        var k;
        var limit;
        if(m.includes("-")) { // all in between
            msplit = m.split("-").map(function(e) {
                if(i == 4) e = month2num(e);
                if(i == 5) e = day2num(e);
                return parseInt(e, 10);
            });
            if (msplit[0] < msplit[1]) {
                for(k = msplit[0]; k  {              // remove duplicates
                //console.log("currentValue=" + k + " ; retValue=" + retValue.toString());
                if(!retValue.includes(k)) retValue.push(k);
            });
            return retValue.sort();        // sort
            //m.split(",").forEach(k => retValue.push(parseInt(k)));
        }
        else if(m.includes("/")) {
            msplit = m.split("/");
            if(msplit[0] == "*") msplit[0] = "0";
            msplit = msplit.map(function(e) {
                return parseInt(e, 10);
            });
            if(i  0; i--) 
            { // start from end of month and look for last specified weekday in that month
                if(parseInt(exp.substring(0,1),10) == new Date(yyyy, mm, i).getDay())
                    return i;
            }
        if(exp.includes("#")) {
            var n = 0;
            for(i = 1; i {
            // instantiate a headers object
            var myHeaders = new Headers();
            // add content type header to object
            myHeaders.append("Content-Type", "application/json");
            // using built in JSON utility package turn object 
            // to string and store in a variable
            var raw = JSON.stringify({"key1":key1});
            // create a JSON object with parameters for API call and store in a variable
            var requestOptions = {
                method: 'POST',
                headers: myHeaders,
                body: raw,
                redirect: 'follow'
            };
            // make API call with parameters and use promises to get response
            fetch("YOUR API INVOKE URL HERE", requestOptions)
            .then(response => response.text())
            .then(result => document.getElementById('result').innerHTML = 
                            result/*alert(JSON.parse(result).body)*/)
            .catch(error => document.getElementById('result').innerHTML = 
                            error/*console.log('error', error)*/);
        }
    



    Enter Cron expression here 
    
    
     Submit
                Result: 

将“YOUR API INVOKE URL HERE”替换为您在上一步中保存的URL。

保存“index.html”,然后ZIP(压缩)它(您可以随意命名ZIP)。

现在返回AWS控制台(您的Amplify应用程序),然后单击“选择文件”,然后打开包含“index.html”的zip 。保存并部署。

就是这样。现在您可以使用“Domain”下的URL打开您的HTML网页。输入一个cron表达式来测试它并单击Submit,您的API应该在Result下返回一个值。

关注
打赏
1665926880
查看更多评论
立即登录/注册

微信扫码登录

0.0888s