Git Product home page Git Product logo

module-core-rql's Introduction

module-core-rql

port from https://github.com/NubeIO/module-core-rql

go build -o module-core-rql

to build and run rubix-os you can use the bash script

bash build.bash <YOUR_ROS_PATH>

example

bash build.bash code/go

examples

droplet alarms

//  GET ALL POINTS BY HOST
let pointsByHost = [];
let pointsByHostByModule = RQL.GetPointsByModuleAllHosts("lora");

// GET ALL POINTS NAMED VOLTAGE AND BELOW VOLTAGE LIMIT
let pointsWithLowVoltage = [];
let lowVolatgeLimit = 4.9;

for (let i = 0; i < pointsByHostByModule.length; i++) {
    let host = pointsByHostByModule[i];
    let hostUUID = host.HostUUID;
    let hostName = host.HostName;
    let points = host.Points;

    for (let i = 0; i < points.length; i++) {
        let point = points[i];
        let pointUUID = point.UUID;
        let pointName = point.Name;
        let sensorID = point.AddressUUID;
        let pv = parseFloat(point.PresentValue);

        if (pointName == "voltage") {
            if (pv < lowVolatgeLimit) {
                pointsWithLowVoltage.push({
                    hostUUID: hostUUID,
                    hostName: hostName,
                    pointUUID: pointUUID,
                    pointName: pointName,
                    presentValue: pv,
                    sensorID: sensorID,
                });
            }
        }
    }
}

let out = [];
let count = 0;

// RAISE THE ALARM!!!
for (let i = 0; i < pointsWithLowVoltage.length; i++) {
    count++;
    let point = pointsWithLowVoltage[i];
    let hostUUID = point.hostUUID;
    let hostName = point.hostName;
    let body = {
        hostUUID: hostUUID,
        entityUUID: point.uuid,
        entityType: "device",
        type: "threshold",
        status: "active",
        severity: "crucial",
        title: "lora sensor low volatge",
        body: `host: ${hostName} sensor-id: ${point.sensorID} value of voltage: ${point.presentValue}`,
        tags: [
            {
                tag: "volatge",
            },
            {
                tag: "droplet",
            },
        ],
    };

    let alert = RQL.AddAlert(hostUUID, body);
    out.push({ count: count, alert: alert });
}

RQL.Result = out;

ping all hosts and add an alert

let groups = RQL.GetAllHostsStatus();

let hostList = [];
for (let group of groups) {
    for (let host of group.Hosts) {
        let newHost = {};
        newHost["name"] = host.Name;
        newHost["uuid"] = host.UUID;
        newHost["count"] = host.PingFailCount;
        hostList.push(newHost);
    }
}

let out = "no alerts";
let alertCount = 0;
let offlineCount = 1;

for (let host of hostList) {
    if (host.count >= offlineCount) {
        let body = {
            hostUUID: host.uuid,
            entityType: "device",
            type: "ping",
            status: "active",
            severity: "crucial",
            body: `host-name: ${host.name} fail count: ${host.count}`,
            tags: [
                {
                    tag: "rubix-compute",
                },
                {
                    tag: "ping",
                },
            ],
        };
        alertCount++;
        RQL.AddAlert(host.uuid, body);
        out = `alert count ${alertCount} host-count: ${hostList.length} fail-ping count: ${host.count}`;
    } else {
        out = `alert count ${alertCount} host-count: ${hostList.length}`;
    }
}

RQL.Result = out;

get all alerts and send a summery to slack

let alerts = RQL.GetAlertsByHost("");

let token = "";
let channel = "C066S807J2D";
let title = `DCJ Alerts ${RQL.Day()} ${RQL.Date()}`;

let colour = "#FF0000";

let message = "";

for (let i = 0; i < alerts.length; i++) {
  let alert = alerts[i];
  let hostName = alert.HostName;
  let alertsCount = alert.TotalAlertsCount;
  let alertsActiveCount = alert.AlertsActiveCount;

  message += `host: *${hostName}*:  total-count: *${alertsCount}* active-count: *${alertsActiveCount}*`;
  message += "\n";
}

RQL.Result = RQL.Slack(token, channel, title, message, colour);

module-core-rql's People

Contributors

nubedev avatar raibnod avatar canuckmarc avatar enjuthulung avatar maharjanaman avatar

Watchers

 avatar Ritesh Shakya avatar  avatar  avatar  avatar

module-core-rql's Issues

Fix RQL Module Disable action

Currently the RQL Module does not disable, please fix.

The Enable function starts go m.Loop(), but there is no channel to stop this go routine.

rules

setup ping/check and raise alert for each offline host

  • run every 1 hour
  • only raise an later if ping fail count is >= 2

lora rules

For each host that has a network of type module-core-loraraw we need to write 2x rules to generate alerts.

  • run every 12 hour
  • voltage threshold will be 3.8

Check voltage level and lastOk

  • if voltage is < 3.8 we need to raise an alert
  • also we need to check the lastOk and if the time is more then 4 hours ago we need to raise an alert
let hostID = "hos_9287616811674038";

RQL.Result = RQL.GetPointsByModuleName(hostID, "module-core-loraraw");

image

Add Alert on scheduled RQL Rule run error.

As RQL will be running a lot of our System Health alerting, it is important that we know if an RQL Rule is failing to run.

When an RQL Rule runs in scheduled mode (on schedule vs. running as a one time "dry run"), if the RQL Rule run fails, then there should be an Alert created. This "Alert on Error" should probably be something that we can enable/disable for each RQL Rule.

Write System Health RQL Scripts

This task is to create the basic System Health RQL rule scripts.

The scope of RQL is described in the document below. Please carefully review and understand this document as it outlines that way that RQL is intended to be used.
https://docs.google.com/document/d/1ImECL8Cylyp1LqN8yXH-NmDUtv4AuR326CsZBpNufNY/edit?usp=sharing

Section 7 of the above document has the required basic System Health Alerts in bold.
image

The first task should be to complete the section 7.2.2.2 Proof of Concept - Design Iteration #1. Please discuss any variations from this scope with me.

Here is my start of the threshold alert RQL script. It was mostly just used for testing the associated APIs in RQL.

// VARIABLES: These should be defined in the RQL Script Variable Config UI
const hosts = ["hos_a6fb0d92546b4776"];
const metaTagID = "HighTemp";
const alertDelayMins = 420;

// the below variables should not be required, but they are because of
// missing features in our platform
const metaTagValues = ["default", "var1", "25"];

// FETCH THE POINTS THAT ARE APPLICABLE TO THIS RULE (MetaTag = "HighTemp")
let points = [];
for (let host of hosts) {
  /*
    let pointOpts = {
        Args: {
           WithMetaTags: true,
           MetaTags: "[{}]"
        },
        HostUUID: point.HostUUID,
    };QL.ROS.GetPointHistoriesByPointUUID(point.UUID, histOpts);
  break;
}
RQL.Result = resp;
// RQL.Result = pointsByHost;
// RQL.Result = points;
// RQL.Result = thisPoint;
*/

    */
  let thisHostPoints = RQL.GetPointsByModuleName(host, "system");
  for (let point of thisHostPoints) {
    for (let metaTag of point.MetaTags) {
      if (metaTag.Key == metaTagID) {
        const reqPointInfo = {
          HostUUID: host,
          UUID: point.UUID,
          Name: point.Name,
          MetaTags: point.MetaTags,
          Tags: point.Tags,
          PresentValue: point.PresentValue,
          Histories: [],
        };
        points.push(reqPointInfo);
      }
    }
  }
}
// RQL.Result = points;

// FETCH THE HISTORIES FOR THE SELECTED POINTS
// calculate the time period for the histories
let nowMillis = Date.now();
let alertDelayMillis = alertDelayMins * 60 * 1000;
let historyStartTimeString = new Date(
  nowMillis - alertDelayMillis
).toISOString();
RQL.Result = historyStartTimeString;
/*
let resp = [];
let thisPoint;
for (let point of points) {
  let histReq = {
    Filter: `point_uuid=pnt_f633f4452ee04fc9`,
    FilterHistory: `timestamp>=${historyStartTimeString}&&value>=20`,
  };
  thisPoint = point;
  resp = RQL.ROS.GetHistories(histReq);
  // let resp = RQL.GetPointHistories(histReq, histOpts);
  // resp = RQL.ROS.GetPointHistoriesByPointUUID(point.UUID, histOpts);
  break;
}
RQL.Result = resp;
// RQL.Result = pointsByHost;
// RQL.Result = points;
// RQL.Result = thisPoint;
*/

[RQL] Improve Variables

Please make the following improvements to RQL Script Variables:

  • Change the Variable property to Value.
  • Enforce JSON parse checks on the variable Value property.
  • Add a Type property to Varibles.
  • Localize variables to specific scripts by adding a ScriptUUID property.
  • Remove the Password Property.

Change the Variable property to Value
There are no existing implementations of RQL Scripts, so this change shouldn't be an issue.

Enforce JSON parse checks on all variable values
Please add a JSON parse check to the Variable create/edit api. Reject the configuration if it doesn't parse as JSON. We should consider whether there is a need for a type change from any to something more restrictive to JSON format.

Add a Type property to Varibles.
Variable Types will later be defined more specifically. This property will allow the UI to use the correct editor for the type of variable.

Localize variables to specific scripts by adding a ScriptUUID property.
RQL Scripts will need to have local variables. Adding a ScriptUUID property will allow us to return only the variables that are specific to the RQL Script.

Add a Required property
In future RQL Scripts will have variables that are required in order for the script to operate properly. This boolean flag will indicate to the UI whether it needs to be completed in order to function.

With the above improvements the updated RQLVariables struct should have this structure:

type RQLVariables struct {
	UUID               string `json:"uuid"`
	ScriptUUID      string `json:"script_uuid"`
	Name              string `json:"name"`
        Type                string `json:"type"`
	Value               any    `json:"value"`
        Required         bool   `json:"required"`
}

example

/*
SCOPE:
get city weather data to dynamically control the indoor zone temperature based of the forecasted outside air temp
 
shutting down outside air vents when there is a dust storm or bush fire


the main goal is to reduce

1. call weather api and get current temp and forecasted temp
2. get current zone temp and shift the zone temp setpoint based on the forecast outside air temp (for example on a colder day lower the set-point)
3. call public holiday API

*/

function setpoint(outsideTemp) {
  let minSp = 18;
  let maxSp = 23;
  let sp = 22;
  if (outsideTemp < minSp) {
    return minSp;
  }

  if (outsideTemp > maxSp) {
    return maxSp;
  }

  if (outsideTemp > 18 && outsideTemp < 20) {
    return minSp + 0.5;
  }
  if (outsideTemp > 19 && outsideTemp < 21) {
    return minSp + 1;
  }
  if (outsideTemp > 21 && outsideTemp < 23) {
    return maxSp;
  }
  return sp;
}

let runAt = "30min";

let response = {};

let apiKey = "b8293d3cba3542838d622151232106";
let city = "Sydney";
let date = RQL.Date();

let fakeAlert = [
  {
    areas: "",
    category: "Other dangers",
    certainty: "",
    desc: "High forest fire danger until significant precipitation.\n\n    Vegetation is very easily ignited and very large areas may be affected.",
    effective: "2023-06-18T08:00:00Z",
    event: "High forest fire danger",
    expires: "2023-06-23T22:00:00Z",
    headline: "Meteorologisk Institutt",
    instruction: "",
    msgtype: "",
    note: "",
    severity: "",
    urgency: "",
  },
];

// date = "2023-12-25" // override the date for testing !!!!!!!!!!FOR TESTING!!!!!!!!!!

let isHolidayResp = RQL.IsPublicHoliday("2023", "AU", date);

let isHoliday = isHolidayResp.Result.IsPublicHoliday;
response.isHoliday = isHoliday;
let hostUUID = "hos_c4be792c63c74454";
if (isHoliday == true) {
  // is a holiday so trun off the A/C
  let pri = {
    P16: 0,
  };

  let pntEnable = "pnt_2bb8530d267140a1";
  RQL.WritePointValue(hostUUID, pntEnable, pri);
  response.turnOffAC = `did turn of AC as is holiday: ${isHolidayResp.Result.Name}`;
} else {
  // is not a holiday so trun on the A/C
  let pri = {
    P16: 1,
  };
  let pntEnable = "pnt_2bb8530d267140a1";
  RQL.WritePointValue(hostUUID, pntEnable, pri);
  response.turnOffAC = `did turn of AC as is holiday: ${isHolidayResp.Result.Name}`;

  // get weather data
  response.turnOffAC = `is not hoilday`;
  let getWeather = RQL.GetCurrentWeather(apiKey, city);
  let outSideAirTemp = getWeather.Result.Current.TempC;
  outSideAirTemp = 21; // override the temp for testing !!!!!!!!!!FOR TESTING!!!!!!!!!!
  response.outSideAirTemp = outSideAirTemp;
  response.weather = `current outside air temp:${outSideAirTemp}, humidity:${getWeather.Result.Current.Humidity},  condition:${getWeather.Result.Current.Condition.Text}`;

  // adjust SP
  pri = {
    P16: setpoint(outSideAirTemp),
  };
  let pntSp = "pnt_d2e2ced50da74b1a";
  let adjustSP = RQL.WritePointValue(hostUUID, pntSp, pri);
  response.adjustSP = `adjusted setpoint to: ${adjustSP.Result.PresentValue}`;

  let = getForecast = RQL.GetForecast(apiKey, city);
  let alerts = fakeAlert; // override the event for testing !!!!!!!!!!FOR TESTING!!!!!!!!!!
  let event = alerts[0].event;
  if (event == "High forest fire danger") {
    // adjust close damper
    pri = {
      P16: 1,
    };
    let pntDmp = "pnt_877a8285a91a43f5";
    let closeDamper = RQL.WritePointValue(hostUUID, pntDmp, pri);
    response.weatherEvent = true;
    response.weatherEventMessage = `closed dampers due to event:${event}`;
  } else {
    pri = {
      P16: 0,
    };
    let pntDmp = "pnt_877a8285a91a43f5";
    let closeDamper = RQL.WritePointValue(hostUUID, pntDmp, pri);
    response.weatherEvent = false;
  }
}

RQL.Result = response; 

update wiki

tags, meta tags

Add examples for calling by tags and meta tags

and use for calling

  • points
  • histoires

add an example of going through history data

Add an example of looping through history data

for example sum all the values

Help Support RQL on DCJ and ESR

Hi @enjuthulung

I'm going on leave for 2.5 weeks starting today. I need you to help push forward the RQL testing while i'm gone.

I have RQL rules running on esr and dcj clients. I have asked the support team (Jerry and Charissa) to monitor the generated alerts and provide feedback on whether they are working or not.

There are a few outstanding RQL/Alert related issues. If you could please implement and test those fixes, then update the dcj and esr servers.

I have disabled the Email Alerts on dcj because it was spamming with emails. Once you build this fix (https://github.com/NubeIO/rubix-os/issues/901) could you please re-enable the email alerts by adding the Support Team into the Alert Conditions.

I have added the RQL Rule Scripts to the RQL repo: #32. The Host UUID (Supervisor) and RQL Rule UUID just need to be updated.

ISSUE: I was just trying to make updates to the esr Offline Gateways and Flatline Points RQL Rule. But when I tried to save my changes, it just gave me a grpc error about it being too large of a file. Seems weird because I was just changing the capitalization of tags => Tags. That being said, i've seen it a couple of times where i've hit save, and it deletes the whole rule script. Currently saving the existing script results in the error. Please investigate.

Overall, we just want to push the testing of these RQL rules forward in my absence. Thanks for your assistance. Please coordinate with Dan and Hilly if you need more information.

[CRASH] Investigate RQL Stability

@RaiBnod can you please investigate the stability of RQL. As we are now using RQL on our main clients, we need to be confident that it is stable. I think it would be good to review the codebase for any obvious issues. Below are some of the things I've noticed.

  1. RQL APIs don't seem to work properly. I can do https://ros-esr.nube-iiot.com/api/modules/module-core-rql/api/rules which returns 3 rules. But if I do https://ros-esr.nube-iiot.com/api/modules/module-core-rql/api/rules/rql_3461426921d5 (where rql_3461426921d5 is one of the existing rules), then it appears to try and RUN THE RULE, instead of just returning the data.
    These 2 APIs call the same function:
  • func GetRule(m *nmodule.Module, r *router.Request) ([]byte, error) {
    return (*m).(*Module).ReuseRuleRun(r.Body, r.PathParams["uuid"])
    }
  • func RunRule(m *nmodule.Module, r *router.Request) ([]byte, error) {
    return (*m).(*Module).ReuseRuleRun(r.Body, r.PathParams["uuid"])
    }
  1. I can see TODO notes in the module. This one says we should add the processes in go routines.

    for _, rule := range allRules { // TODO add a lock, so we can add a goroutine

  2. We just observed RQL locking up and not recognizing an existing RQL rule. This caused the whole server to become too slow to use. I see that in the RQL module that many functions use the name of the rule, rather than the UUID, to reference the rule; seems like this might cause issues?

Aug 21 04:22:22 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:22.775Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:23 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:23.785Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:24 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:24.792Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:25 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:25.796Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:26 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:26.801Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:27 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:27.810Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:28 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:28.815Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:29 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:29.823Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:30 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:30.828Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:31 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:31.832Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:32 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:32.837Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:33 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:33.843Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:34 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:34.849Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:35 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:35.856Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:36 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:36.861Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:37 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:37.865Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:38 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:38.871Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:39 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:39.876Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:40 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:40.883Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:41 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:41.889Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:42 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:42.895Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:43 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:43.899Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:44 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:44.906Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:45 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:45.911Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:46 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:46.917Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:47 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:47.923Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:48 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:48.928Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:49 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:49.933Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:50 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:50.940Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:51 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:51.944Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:52 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:52.950Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
Aug 21 04:22:53 nubeio-nubeio-stack-rubix-esr-0 rubix-os[563054]: 2024-08-21T04:22:53.954Z [DEBUG] plugin.module-core-rql-amd64: level=error msg="module-core-rql: run rules loop execute err: rule:Offline Gateway and Flatline Points does not exist"
  1. You can see in this RQL rule results, that it was running successfully, but then it started getting errors in the last 2 runs. There were no changes to the rule during this time, and the timing is the same as the error above.
{
        "uuid": "rql_3461426921d5",
        "name": "Offline Gateway and Flatline Points",
        "latest_run_date": "",
        "script": "let activeGatewayAlertsCount = 0;\nlet closedGatewayAlertsCount = 0;\nlet activeFlatlineAlertsCount = 0;\nlet closedFlatlineAlertsCount = 0;\nconst enableDebug = false;\nlet debug = {}; // Debugging object to store important values\nlet errors = [];\nconst flatlineDefaultAlertDelayHours = 24;\nconst flatlineAlertDelayMetaTagKey = \"flatlineAlertDelay\";\nconst serverHostUUID = \"hos_9a56c77f7cbe4038\";\nconst ruleUUID = \"rql_3461426921d5\";\n\nfunction getAlertsForHost(hostUUID, sourceUUID, entityType, type) {\n  try {\n    const opts = {\n      Args: {\n        Source: sourceUUID,\n        Statuses: [\"active\", \"acknowledged\"],\n      },\n      HostUUID: hostUUID,\n    };\n    const alerts = RQL.ROS.GetAlerts(opts);\n    return alerts.filter(\n      (alert) => alert.EntityType == entityType && alert.Type == type\n    );\n  } catch (error) {\n    throw error;\n  }\n}\n\nfunction addGatewayOfflineAlert(rqlRuleUUID, serverHostUUID, host) {\n  try {\n    const alert = {\n      HostUUID: serverHostUUID,\n      EntityType: \"gateway\",\n      EntityUUID: host.UUID,\n      Type: \"ping\",\n      Status: \"\",\n      Severity: \"crucial\",\n      Title: `${host.Name} - Gateway Offline`,\n      Body: `${host.Name} - Gateway Offline`,\n      Tags: [\n        {\n          tag: \"ping\",\n        },\n        {\n          tag: \"offline\",\n        },\n        {\n          tag: \"health\",\n        },\n      ],\n      Source: rqlRuleUUID,\n    };\n    return RQL.ROS.CreateAlert(alert);\n  } catch (error) {\n    throw error;\n  }\n}\n\nfunction closeAlert(serverHostUUID, alertUUID) {\n  try {\n    return RQL.UpdateAlertStatus(serverHostUUID, alertUUID, \"closed\");\n  } catch (error) {\n    throw error;\n  }\n}\n\n// Function to get the current time minus a specified number of hours\nfunction getTimeNHoursBeforeNow(n) {\n  const now = new Date();\n  now.setTime(now.getTime() - n * 60 * 60 * 1000); // n * 60 * 60 * 1000 converts hours to milliseconds\n  return now.toISOString();\n}\n\n// Function to get networks from a host\nfunction getNetworks(hostUUID) {\n  try {\n    const opts = {\n      Args: {\n        WithDevices: true,\n        WithPoints: true,\n        WithMetaTags: true,\n      },\n      HostUUID: hostUUID,\n    };\n    const body = {};\n    return RQL.ROS.GetNetworks(body, opts);\n  } catch (error) {\n    throw error;\n  }\n}\n\n// Function to get a host\nfunction getHost(hostUUID) {\n  try {\n    const opts = {};\n    return RQL.ROS.GetHost(hostUUID, opts);\n  } catch (error) {\n    throw error;\n  }\n}\n\n// Function to check if a point is flatlining (all the same value) or offline (no values)\nfunction checkPointFlatLineOffline(hostUUID, pointUUID, alertDelayHours) {\n  try {\n    const timestamp = getTimeNHoursBeforeNow(alertDelayHours);\n    const body = {\n      Filter: `host_uuid=${hostUUID}&&point_uuid=${pointUUID}`,\n      FilterHistory: `timestamp>=${timestamp}`,\n    };\n    const opts = { Args: {} };\n    res = RQL.ROS.GetHistories(body, opts);\n    if (res.Data.length > 0) {\n      const values = res.Data.flatMap((data) =>\n        data.Values.map((item) => +item.Value)\n      );\n      if (enableDebug) {\n        debug[hostUUID][pointUUID][\"values\"] = values;\n      }\n      // check offline (no history values)\n      if (values.length == 0) {\n        return true;\n      }\n      // check flatline (all history values the same)\n      const val = values[0];\n      return values.every((value) => value == val);\n    }\n    // offline (no history values), or history query failure\n    return true;\n  } catch (error) {\n    throw error;\n  }\n}\n\nfunction getPoint(hostUUID, pointUUID) {\n  try {\n    const opts = {\n      Args: {},\n      HostUUID: hostUUID,\n    };\n    return RQL.ROS.GetPoint(pointUUID, opts);\n  } catch (error) {\n    throw error;\n  }\n}\n\n// Function to get the delay hours from a MetaTag or Point\nfunction getDelayHoursFromMetaTag(metaTag, defaultDelayHours) {\n  try {\n    if (metaTag.Value == \"default\") {\n      // use the default value\n      return defaultDelayHours;\n    } else if (!isNaN(metaTag.Value)) {\n      // use the numeric value\n      return +metaTag.Value;\n    } else {\n      // get the host and point uuids from the meta-tag value\n      const regex = /(hos_[a-zA-Z0-9]{16})|(pnt_[a-zA-Z0-9]{16})/g;\n      const matches = metaTag.Value.match(regex);\n      let HostUUID = null;\n      let PointUUID = null;\n      if (matches) {\n        matches.forEach((match) => {\n          if (match.startsWith(\"hos_\")) {\n            HostUUID = match;\n          } else if (match.startsWith(\"pnt_\")) {\n            PointUUID = match;\n          }\n        });\n        if (HostUUID != null && PointUUID != null) {\n          const point = getPoint(HostUUID, PointUUID);\n          return parseFloat(point?.PresentValue);\n        }\n      } else {\n        return null;\n      }\n    }\n  } catch (_) {\n    return null;\n  }\n}\n\nfunction addPointFlatlineOfflineAlert(\n  rqlRuleUUID,\n  serverHostUUID,\n  host,\n  device,\n  point\n) {\n  try {\n    const alert = {\n      HostUUID: serverHostUUID,\n      EntityType: \"point\",\n      EntityUUID: point.UUID,\n      Type: \"flat-line\",\n      Status: \"\",\n      Severity: \"warning\",\n      Title: `${host.Name} - ${device.Name} - ${point.Name} - Sensor Offline/Flatline`,\n      Body: `${host.Name} - ${device.Name} - ${point.Name} - Sensor Offline/Flatline\\n\n            Host: ${host.Name} - ${host.UUID}\n            Device: ${device.Name} - ${device.UUID}\n            Point: ${point.Name} - ${point.UUID}\n      `,\n      Tags: [\n        {\n          tag: \"flatline\",\n        },\n        {\n          tag: \"offline\",\n        },\n        {\n          tag: \"health\",\n        },\n      ],\n      Source: rqlRuleUUID,\n    };\n    return RQL.ROS.CreateAlert(alert);\n  } catch (error) {\n    throw error;\n  }\n}\n\n// Step 1: Gateway Offline Alerts\nconst onlineHosts = [];\nconst existingGatewayAlerts = getAlertsForHost(\n  serverHostUUID,\n  ruleUUID,\n  \"gateway\",\n  \"ping\"\n);\nif (enableDebug) {\n  debug[\"existingGatewayAlerts\"] = existingGatewayAlerts;\n}\ngroups = RQL.ROS.GetGroups();\nfor (let group of groups) {\n  if (enableDebug) {\n    debug[group.UUID] = {};\n  }\n  try {\n    hostStatusResult = RQL.ROS.UpdateHostsStatus(group?.UUID);\n  } catch (error) {\n    errors.push(error.message || error);\n  }\n  for (let host of hostStatusResult?.Hosts) {\n    try {\n      if (enableDebug) {\n        debug[group.UUID][host.UUID] = {};\n        debug[group.UUID][host.UUID][\"PingFailCount\"] = host.PingFailCount;\n      }\n      let existingGatewayAlert = null;\n      for (let alert of existingGatewayAlerts) {\n        if (alert.EntityUUID == host.UUID) {\n          existingGatewayAlert = alert;\n          break;\n        }\n      }\n      if (enableDebug) {\n        debug[group.UUID][host.UUID][\"existingGatewayAlert\"] =\n          existingGatewayAlert;\n      }\n      if (host.PingFailCount > 0) {\n        addGatewayOfflineAlert(ruleUUID, serverHostUUID, host);\n        activeGatewayAlertsCount++;\n        if (enableDebug) {\n          debug[group.UUID][host.UUID][\"alerts\"] = {\n            Name: host.Name,\n            PingFailCount: host.PingFailCount,\n            AlertType: \"Gateway Offline\",\n          };\n        }\n      } else {\n        onlineHosts.push(host.UUID);\n        if (\n          existingGatewayAlert != null &&\n          (existingGatewayAlert.Status == \"active\" ||\n            existingGatewayAlert.Status == \"acknowledged\")\n        ) {\n          closeAlert(serverHostUUID, existingGatewayAlert.UUID);\n          closedGatewayAlertsCount++;\n        }\n      }\n    } catch (error) {\n      errors.push(error.message || error);\n    }\n  }\n  if (enableDebug) {\n    debug[\"onlineHosts\"] = onlineHosts;\n  }\n}\n\n// Step 2: Sensor FlatLine/NoData Alerts for online Gateways\nconst existingFlatlineAlerts = getAlertsForHost(\n  serverHostUUID,\n  ruleUUID,\n  \"point\",\n  \"flat-line\"\n);\nif (enableDebug) {\n  debug[\"existingFlatlineAlerts\"] = existingFlatlineAlerts;\n}\nfor (const hostUUID of onlineHosts) {\n  try {\n    if (enableDebug) {\n      debug[hostUUID] = {};\n    }\n    const networks = getNetworks(hostUUID);\n    let networkDisable = false;\n    let deviceDisable = false;\n    let pointDisable = false;\n    for (const network of networks) {\n      networkDisable = false;\n      if (network.Enable == false || network.HistoryEnable == false) {\n        networkDisable = true;\n      }\n\n      for (const device of network.Devices) {\n        deviceDisable = false;\n        if (device.Enable == false || device.HistoryEnable == false) {\n          deviceDisable = true;\n        }\n\n        for (const point of device.Points) {\n          pointDisable = false;\n          if (point.Enable == false || point.HistoryEnable == false) {\n            pointDisable = true;\n          }\n\n          try {\n            const metaTag = point.MetaTags.find(\n              (tag) => tag.Key == flatlineAlertDelayMetaTagKey\n            );\n\n            const overallDisable =\n              networkDisable || deviceDisable || pointDisable;\n            if (metaTag) {\n              if (enableDebug) {\n                debug[hostUUID][point.UUID] = {};\n                debug[hostUUID][point.UUID][\"Name\"] = point.Name;\n                debug[hostUUID][point.UUID][\"metaTag\"] = metaTag;\n              }\n              let flatline = false;\n              if (!overallDisable) {\n                let alertDelayHours = getDelayHoursFromMetaTag(\n                  metaTag,\n                  flatlineDefaultAlertDelayHours\n                );\n                if (alertDelayHours == null) {\n                  if (enableDebug) {\n                    debug[hostUUID][point.UUID][\"alertDelayHours\"] = \"error\";\n                  }\n                  errors.push(\n                    `host(${hostUUID}) point(${point.UUID}) invalid ${flatlineAlertDelayMetaTagKey} meta-tag value`\n                  );\n                  alertDelayHours = flatlineDefaultAlertDelayHours;\n                } else {\n                  if (enableDebug) {\n                    debug[hostUUID][point.UUID][\"alertDelayHours\"] =\n                      alertDelayHours;\n                  }\n                }\n\n                flatline = checkPointFlatLineOffline(\n                  hostUUID,\n                  point.UUID,\n                  alertDelayHours\n                );\n                if (enableDebug) {\n                  debug[hostUUID][point.UUID][\"flatline\"] = flatline;\n                }\n\n                if (flatline) {\n                  const host = getHost(hostUUID);\n                  addPointFlatlineOfflineAlert(\n                    ruleUUID,\n                    serverHostUUID,\n                    host,\n                    device,\n                    point\n                  );\n                  activeFlatlineAlertsCount++;\n                  if (enableDebug) {\n                    debug[hostUUID][point.UUID][\"alerts\"] = {\n                      Name: point.Name,\n                      AlertType: \"Flatline\",\n                    };\n                  }\n                }\n              }\n\n              if (!flatline) {\n                for (const existingAlert of existingFlatlineAlerts) {\n                  if (\n                    existingAlert.EntityUUID == point.UUID &&\n                    (existingAlert.Status == \"active\" ||\n                      existingAlert.Status == \"acknowledged\")\n                  ) {\n                    const host = getHost(hostUUID);\n                    closeAlert(serverHostUUID, existingAlert.UUID);\n                    closedFlatlineAlertsCount++;\n                  }\n                }\n              }\n            }\n          } catch (error) {\n            errors.push(error.message || error);\n          }\n        }\n      }\n    }\n  } catch (error) {\n    if (enableDebug) {\n      debug[hostUUID][\"error\"] = error.message || error;\n    }\n  }\n}\n\n// Final Result with Debugging Info\nif (enableDebug) {\n  RQL.Result = {\n    Alerts: {\n      ActiveGatewayAlerts: activeGatewayAlertsCount,\n      GatewayAlertsClosed: closedGatewayAlertsCount,\n      ActiveFlatlineAlerts: activeFlatlineAlertsCount,\n      FlatlineAlertsClosed: closedFlatlineAlertsCount,\n    },\n    Errors: errors,\n    DebugInfo: debug,\n  };\n} else {\n  RQL.Result = {\n    Alerts: {\n      ActiveGatewayAlerts: activeGatewayAlertsCount,\n      GatewayAlertsClosed: closedGatewayAlertsCount,\n      ActiveFlatlineAlerts: activeFlatlineAlertsCount,\n      FlatlineAlertsClosed: closedFlatlineAlertsCount,\n    },\n    Errors: errors,\n  };\n}\n",
        "schedule": "60 minutes",
        "enable": false,
        "result_storage_size": 50,
        "result": [
            {
                "result": {
                    "Alerts": {
                        "ActiveAlerts": 24,
                        "AlertsClosed": 1
                    },
                    "DebugInfo": {},
                    "Errors": []
                },
                "timestamp": "Thu, 15 Aug 2024 06:43:41 UTC",
                "time": "2024-08-15T06:43:41.873260029Z"
            },
            {
                "result": {
                    "Alerts": {
                        "ActiveAlerts": 24,
                        "AlertsClosed": 0
                    },
                    "DebugInfo": {},
                    "Errors": []
                },
                "timestamp": "Thu, 15 Aug 2024 07:46:43 UTC",
                "time": "2024-08-15T07:46:43.267496386Z"
            },
            {
                "result": {
                    "Alerts": {
                        "ActiveAlerts": 24,
                        "AlertsClosed": 0
                    },
                    "DebugInfo": {},
                    "Errors": []
                },
                "timestamp": "Thu, 15 Aug 2024 08:49:39 UTC",
                "time": "2024-08-15T08:49:39.860293615Z"
            },
            {
                "result": {
                    "Alerts": {
                        "ActiveAlerts": 24,
                        "AlertsClosed": 0
                    },
                    "DebugInfo": {},
                    "Errors": []
                },
                "timestamp": "Thu, 15 Aug 2024 09:52:15 UTC",
                "time": "2024-08-15T09:52:15.040901239Z"
            },
            {
                "result": {
                    "Alerts": {
                        "ActiveAlerts": 24,
                        "AlertsClosed": 0
                    },
                    "DebugInfo": {},
                    "Errors": []
                },
                "timestamp": "Thu, 15 Aug 2024 10:55:03 UTC",
                "time": "2024-08-15T10:55:03.849918794Z"
            },
            {
                "result": {
                    "Alerts": {
                        "ActiveAlerts": 25,
                        "AlertsClosed": 0
                    },
                    "DebugInfo": {},
                    "Errors": []
                },
                "timestamp": "Thu, 15 Aug 2024 11:57:29 UTC",
                "time": "2024-08-15T11:57:29.718063828Z"
            },
            {
                "result": {
                    "Alerts": {
                        "ActiveAlerts": 25,
                        "AlertsClosed": 0
                    },
                    "DebugInfo": {},
                    "Errors": []
                },
                "timestamp": "Thu, 15 Aug 2024 12:59:41 UTC",
                "time": "2024-08-15T12:59:41.525904545Z"
            },
            {
                "result": {
                    "Alerts": {
                        "ActiveAlerts": 25,
                        "AlertsClosed": 0
                    },
                    "DebugInfo": {},
                    "Errors": []
                },
                "timestamp": "Thu, 15 Aug 2024 14:01:52 UTC",
                "time": "2024-08-15T14:01:52.242822961Z"
            },
            {
                "result": {
                    "Alerts": {
                        "ActiveAlerts": 25,
                        "AlertsClosed": 0
                    },
                    "DebugInfo": {},
                    "Errors": []
                },
                "timestamp": "Thu, 15 Aug 2024 15:03:59 UTC",
                "time": "2024-08-15T15:03:59.478894224Z"
            },
            {
                "result": {
                    "Alerts": {
                        "ActiveAlerts": 25,
                        "AlertsClosed": 0
                    },
                    "DebugInfo": {},
                    "Errors": []
                },
                "timestamp": "Thu, 15 Aug 2024 16:06:02 UTC",
                "time": "2024-08-15T16:06:02.289333238Z"
            },
            {
                "result": {
                    "Alerts": {
                        "ActiveAlerts": 25,
                        "AlertsClosed": 0
                    },
                    "DebugInfo": {},
                    "Errors": []
                },
                "timestamp": "Thu, 15 Aug 2024 17:08:08 UTC",
                "time": "2024-08-15T17:08:08.771767722Z"
            },
            {
                "result": {
                    "Alerts": {
                        "ActiveAlerts": 25,
                        "AlertsClosed": 0
                    },
                    "DebugInfo": {},
                    "Errors": []
                },
                "timestamp": "Thu, 15 Aug 2024 18:10:21 UTC",
                "time": "2024-08-15T18:10:21.485311673Z"
            },
            {
                "result": {
                    "Alerts": {
                        "ActiveAlerts": 24,
                        "AlertsClosed": 1
                    },
                    "DebugInfo": {},
                    "Errors": []
                },
                "timestamp": "Thu, 15 Aug 2024 19:12:29 UTC",
                "time": "2024-08-15T19:12:29.77855625Z"
            },
            {
                "result": {
                    "Alerts": {
                        "ActiveFlatlineAlerts": 10,
                        "ActiveGatewayAlerts": 26,
                        "FlatlineAlertsClosed": 94,
                        "GatewayAlertsClosed": 0
                    },
                    "DebugInfo": {},
                    "Errors": []
                },
                "timestamp": "Sun, 18 Aug 2024 22:23:50 UTC",
                "time": "2024-08-18T22:23:50.223116224Z"
            },
            {
                "result": "GoError: Post \"http://10.8.1.1:1660/grpc\": dial tcp 10.8.1.1:1660: connect: connection refused at getAlertsForHost (<eval>:27:5(33))",
                "timestamp": "Wed, 21 Aug 2024 04:34:48 UTC",
                "time": "2024-08-21T04:34:48.607505253Z"
            },
            {
                "result": "GoError: Post \"http://10.8.1.1:1660/grpc\": dial tcp 10.8.1.1:1660: connect: connection refused at getAlertsForHost (<eval>:27:5(33))",
                "timestamp": "Wed, 21 Aug 2024 04:34:50 UTC",
                "time": "2024-08-21T04:34:50.157629512Z"
            }
        ]
    }

[BUG] CreateAlert() with Tags fails... Sometimes

@RaiBnod Having a strange issue with RQL creating Alerts with tags (sometimes).

I found that I was getting errors on creating alerts with Tags from RQL, but I can't figure out why. It works fine in one RQL rule, but not for another RQL rule. I have code snippets below, and have attached the full RQL rules (from DCJ supervisor). I have been able to replicate this same issue on my PC.

The error is like this:

ERRO[2024-08-22T09:47:23+10:00] INSERT INTO `tags` DEFAULT VALUES ON CONFLICT DO NOTHING RETURNING `tag` (18.729µs)  error="near \"ON\": syntax error"
ERRO[2024-08-22T09:47:23+10:00] INSERT INTO `alerts` (`uuid`,`host_uuid`,`entity_type`,`entity_uuid`,`type`,`status`,`severity`,`target`,`title`,`body`,`source`,`notified`,`notified_at`,`emailed`,`emailed_at`,`created_at`,`last_updated`) VALUES ("alt_e9f478a17d934392","hos_a6fb0d92546b4776","point","pnt_77fd6cf0614942f7","threshold","active","warning","none","localhost - RQL_Test_1 - Temperature_1 - Low Battery Alert","localhost - RQL_Test_1 - Temperature_1 - Low Battery Alert

            Host: localhost - hos_a6fb0d92546b4776

            Device: RQL_Test_1 - dev_c995d8c14a414b7c

            Point: Temperature_1 - pnt_77fd6cf0614942f7

            Alert: Point value has been less than the Low Battery Alert Threshold (25) for 12 hours.

      ","rql_bbbfe11c8ad8",false,NULL,false,NULL,"2024-08-21 23:47:23.745","2024-08-21 23:47:23.745") (398.511µs)  error="near \"ON\": syntax error; near \"ON\": syntax error"
CreateAlert() Create(&body) error: near "ON": syntax error; near "ON": syntax error
ERRO[2024-08-22T09:47:23+10:00] near "ON": syntax error; near "ON": syntax error 

The function that causes this error is this one (from the Low Battery Alert RQL rule):

function addLowThresholdAlert(
  rqlRuleUUID,
  serverHostUUID,
  host,
  device,
  point,
  alertThreshold,
  alertDelayHours
) {
  try {
    const alert = {
      HostUUID: serverHostUUID,
      EntityType: "point",
      EntityUUID: point.UUID,
      Type: "threshold",
      Status: "",
      Severity: "warning",
      Title: `${host.Name} - ${device.Name} - ${point.Name} - Low Battery Alert`,
      Body: `${host.Name} - ${device.Name} - ${point.Name} - Low Battery Alert\n
            Host: ${host.Name} - ${host.UUID}\n
            Device: ${device.Name} - ${device.UUID}\n
            Point: ${point.Name} - ${point.UUID}\n
            Alert: Point value has been less than the Low Battery Alert Threshold (${alertThreshold}) for ${alertDelayHours} hours.\n
      `,
      Tags: [
        {
          tag: "threshold",
        },
        {
          tag: "low",
        },
        {
          tag: "battery",
        },
      ],
      Source: rqlRuleUUID,
    };
    return RQL.ROS.CreateAlert(alert);
  } catch (error) {
    if (enableDebug) {
      debug[host.UUID][point.UUID]["addLowThresholdAlert error"] =
        error.message || error;
    }
    throw error;
  }
}

But doing the same function with the Tags removed works fine:

function addLowThresholdAlert(
  rqlRuleUUID,
  serverHostUUID,
  host,
  device,
  point,
  alertThreshold,
  alertDelayHours
) {
  try {
    const alert = {
      HostUUID: serverHostUUID,
      EntityType: "point",
      EntityUUID: point.UUID,
      Type: "threshold",
      Status: "",
      Severity: "warning",
      Title: `${host.Name} - ${device.Name} - ${point.Name} - Low Battery Alert`,
      Body: `${host.Name} - ${device.Name} - ${point.Name} - Low Battery Alert\n
            Host: ${host.Name} - ${host.UUID}\n
            Device: ${device.Name} - ${device.UUID}\n
            Point: ${point.Name} - ${point.UUID}\n
            Alert: Point value has been less than the Low Battery Alert Threshold (${alertThreshold}) for ${alertDelayHours} hours.\n
      `,
      Tags: [],
      Source: rqlRuleUUID,
    };
    return RQL.ROS.CreateAlert(alert);
  } catch (error) {
    if (enableDebug) {
      debug[host.UUID][point.UUID]["addLowThresholdAlert error"] =
        error.message || error;
    }
    throw error;
  }
}

This issue is happening on the Low Battery Alert RQL rule, but I can successfully create Alerts with tags on the Offline Gateways and Flatline Points RQL rule, where the alert creation function is basically the same (see below).

function addPointFlatlineOfflineAlert(
  rqlRuleUUID,
  serverHostUUID,
  host,
  device,
  point
) {
  try {
    const alert = {
      HostUUID: serverHostUUID,
      EntityType: "point",
      EntityUUID: point.UUID,
      Type: "flat-line",
      Status: "",
      Severity: "warning",
      Title: `${host.Name} - ${device.Name} - ${point.Name} - Sensor Offline/Flatline`,
      Body: `${host.Name} - ${device.Name} - ${point.Name} - Sensor Offline/Flatline\n
            Host: ${host.Name} - ${host.UUID}
            Device: ${device.Name} - ${device.UUID}
            Point: ${point.Name} - ${point.UUID}
      `,
      Tags: [
        {
          tag: "flatline",
        },
        {
          tag: "offline",
        },
        {
          tag: "health",
        },
      ],
      Source: rqlRuleUUID,
    };
    return RQL.ROS.CreateAlert(alert);
  } catch (error) {
    throw error;
  }
}

Screenshot shows Alerts and Tags created successfully for the above RQL rule:
image

NULL pointer exception

Oct 18 04:17:33 nubeio-nubeio-stack-rubix-nubeio-0 rubix-os[318318]: 2023-10-18T04:17:33.082Z [DEBUG] plugin.module-core-rql-amd64: panic: runtime error: invalid memory address or nil pointer dereference
Oct 18 04:17:33 nubeio-nubeio-stack-rubix-nubeio-0 rubix-os[318318]: 2023-10-18T04:17:33.082Z [DEBUG] plugin.module-core-rql-amd64: [signal SIGSEGV: segmentation violation code=0x1 addr=0xf8 pc=0xec0f17]
Oct 18 04:17:33 nubeio-nubeio-stack-rubix-nubeio-0 rubix-os[318318]: 2023-10-18T04:17:33.082Z [DEBUG] plugin.module-core-rql-amd64:
Oct 18 04:17:33 nubeio-nubeio-stack-rubix-nubeio-0 rubix-os[318318]: 2023-10-18T04:17:33.082Z [DEBUG] plugin.module-core-rql-amd64: goroutine 43 [running]:
Oct 18 04:17:33 nubeio-nubeio-stack-rubix-nubeio-0 rubix-os[318318]: 2023-10-18T04:17:33.082Z [DEBUG] plugin.module-core-rql-amd64: github.com/NubeIO/module-core-rql/pkg.returnType({0x12bbae8, 0x1b4b400})
Oct 18 04:17:33 nubeio-nubeio-stack-rubix-nubeio-0 rubix-os[318318]: 2023-10-18T04:17:33.082Z [DEBUG] plugin.module-core-rql-amd64:         /home/runner/work/module-core-rql/module-core-rql/pkg/endpoints.go:200 +0x77
Oct 18 04:17:33 nubeio-nubeio-stack-rubix-nubeio-0 rubix-os[318318]: 2023-10-18T04:17:33.082Z [DEBUG] plugin.module-core-rql-amd64: github.com/NubeIO/module-core-rql/pkg.(*Module).Loop(0xc0002aab40)
Oct 18 04:17:33 nubeio-nubeio-stack-rubix-nubeio-0 rubix-os[318318]: 2023-10-18T04:17:33.082Z [DEBUG] plugin.module-core-rql-amd64:         /home/runner/work/module-core-rql/module-core-rql/pkg/loop.go:61 +0x2c5
Oct 18 04:17:33 nubeio-nubeio-stack-rubix-nubeio-0 rubix-os[318318]: 2023-10-18T04:17:33.082Z [DEBUG] plugin.module-core-rql-amd64: created by github.com/NubeIO/module-core-rql/pkg.(*Module).Enable in goroutine 42
Oct 18 04:17:33 nubeio-nubeio-stack-rubix-nubeio-0 rubix-os[318318]: 2023-10-18T04:17:33.082Z [DEBUG] plugin.module-core-rql-amd64:         /home/runner/work/module-core-rql/module-core-rql/pkg/enable.go:31 +0x3d3
Oct 18 04:17:33 nubeio-nubeio-stack-rubix-nubeio-0 rubix-os[318318]: 2023-10-18T04:17:33.085Z [DEBUG] plugin.stdio: received EOF, stopping recv loop: err="rpc error: code = Unavailable desc = error reading from server: EOF"
Oct 18 04:17:33 nubeio-nubeio-stack-rubix-nubeio-0 rubix-os[318318]: 2023-10-18T04:17:33.086Z [ERROR] plugin: plugin process exited: path=/data/rubix-os/data/modules/module-core-rql/v0.0.3/module-core-rql-amd64 pid=318325 error="exit status 2"

These are the data, remove the .txt filetype; we are just attaching that filetype for tweaking the GitHub validation:

RQLRule.txt
RQLVariables.txt

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.