I have an app that needs to send out notification/s everyday with random messages to user depending on how many notification they want (up to 5 notifs per day) and between what time they want (for example notifications will fire only between 6:00am - 9:00am everyday).
To elaborate I'm building a functionality with an idea to send out random inspirational messages that I'm pulling from a hardcoded array variable or json file.
Currently I'm using this package: https://github.com/zo0r/react-native-push-notification to create local notification.
I tried the idea of setting a function that returns a string for the message parameter of localNotificationSchedule, but when I do this, instead of using a regular string, it's not showing the notification.
PushNotification.localNotificationSchedule({
id : '1',
userInfo : { id: userId },
message : () => {
return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5); //trying to return random string every time notification fires.
},
date : moment(Date.now()).add(2, 'seconds').toDate(),
repeatType : 'day',
});
I considered using other approach such as react-native headless JS but it's for android only.
Also considered using https://www.npmjs.com/package/react-native-background-fetch. But I have a complex interval for notifications. For example, the user might set the notification to run from 6:00am - 6:30am everyday and set to fire 5 notifications. In this interval, notifications will run every 6 mins.
But react-native-background-fetch' minimal interval is only 15 minutes.
I know that this can be done by using a push notification instead, but with that, user will need a connection in order for them to receive a notification, which is not ideal for this case.
Iv'e seen this from an Ios app so I know this is possible to achieve.
As per the dev, you can try calling PushNotification.localNotificationSchedule multiple times.
What I've done is this:
const messages = [{text:'',time:0}...];
messages.map(message=>{
PushNotification.localNotificationSchedule({
//... You can use all the options from localNotifications
channelId: "my-channel",
message: message.text, // (required)
date: new Date(Date.now() + (60 + message.time) * 1000), // in 60 secs
});
})
to show a message from the messages array separated by 5 seconds.
Related
For a mental health app project, I need to intercept the startup of specific apps (like Instagram) and check if they used instagram the n-th time, possibly opening a questionair etc.
Searching for a solutions online, I came across the "android.app.usage" API. I could not get my around how to use this.
Do I need a for every running background service which does active polling with the usage api?
Or is their a way to say "run this code or start this app/service when appXY launches"?
Looking forward to any kind of input :)
Greetings Pascal
You can't listen out for an "app is being opened" intent unfortunately, Android doesn't support it. Your approach is likely the best workaround, to state it explicitly:
Have a foreground service running (so it is less likely to be killed by the OS) at all times.
Check regularly the currently running app, and see if it's the one you're trying to look for.
If this is different to last time you checked, do whatever you need to. Perhaps this will include keeping track of last time the app was opened, how many times it's been opened etc.
As a warning however, the OS won't really like this, and there's likely to be an impact on battery life. Whatever you do, make sure this check isn't happening when the screen is off, happening as infrequently as possible, and doesn't include any unnecessary computation, otherwise the user will quickly notice the negative impact.
Here's an extract from an article that looks like it'll be able to fetch the latest app even on later versions:
var foregroundAppPackageName : String? = null
val currentTime = System.currentTimeMillis()
// The `queryEvents` method takes in the `beginTime` and `endTime` to retrieve the usage events.
// In our case, beginTime = currentTime - 10 minutes ( 1000 * 60 * 10 milliseconds )
// and endTime = currentTime
val usageEvents = usageStatsManager.queryEvents( currentTime - (1000*60*10) , currentTime )
val usageEvent = UsageEvents.Event()
while ( usageEvents.hasNextEvent() ) {
usageEvents.getNextEvent( usageEvent )
Log.e( "APP" , "${usageEvent.packageName} ${usageEvent.timeStamp}" )
}
I have three activities. Login,Create Account activity and PostAccountActivity in my app. When Click Create account button I get a crash with the following output on the logcat window
2021-02-03 11:31:47.430 4954-4989/com.example.fauth E/AndroidRuntime: FATAL EXCEPTION: grpc-default-executor-0
Process: com.example.fauth, PID: 4954
java.lang.AssertionError
at io.grpc.internal.DnsNameResolver.getResourceResolver(DnsNameResolver.java:536)
at io.grpc.internal.DnsNameResolver.access$500(DnsNameResolver.java:60)
at io.grpc.internal.DnsNameResolver$1.run(DnsNameResolver.java:211)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
Go to Firebase console > click your project > cloud firestore > rules.....Edit the timestamp date to a date that you want, probably a future date. Because for me the timestamp date had already passed so I had to adjust to a more future date. Dont forget to change the version of your rules too.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// This rule allows anyone with your database reference to view, edit,
// and delete all data in your Firestore database. It is useful for getting
// started, but it is configured to expire after 30 days because it
// leaves your app open to attackers. At that time, all client
// requests to your Firestore database will be denied.
//
// Make sure to write security rules for your app before that time, or else
// all client requests to your Firestore database will be denied until you Update
// your rules
match /{document=**} {
allow read, write: if true;
allow read, write: if request.time < timestamp.date(2022, 12, 30);
}
}
}
I need to get the data from my pubsub message and insert into bigquery.
What I have:
const topicName = "-----topic-name-----";
const data = JSON.stringify({ foo: "bar" });
// Imports the Google Cloud client library
const { PubSub } = require("#google-cloud/pubsub");
// Creates a client; cache this for further use
const pubSubClient = new PubSub();
async function publishMessageWithCustomAttributes() {
// Publishes the message as a string, e.g. "Hello, world!" or JSON.stringify(someObject)
const dataBuffer = Buffer.from(data);
// Add two custom attributes, origin and username, to the message
const customAttributes = {
origin: "nodejs-sample",
username: "gcp",
};
const messageId = await pubSubClient
.topic(topicName)
.publish(dataBuffer, customAttributes);
console.log(`Message ${messageId} published.`);
}
publishMessageWithCustomAttributes().catch(console.error);
I need to get the data/attributes from this message and query in BigQuery, anyone can help me?
Thaks in advance!
In fact, there is 2 solutions to consume the messages: either a message per message, or in bulk.
Firstly, before going in detail, and because you will perform BigQuery calls (or Facebook API calls), you will spend a lot of the processing time to wait the API response.
Message per Message
If you have an acceptable volume of message, you can perform a message per message processing. You have 2 solutions here:
You can handle each message with Cloud Functions. Set the minimal amount of memory to the functions (128Mb) to limit the CPU cost and thus the global cost. Indeed, because you will wait a lot, don't spend expensive CPU cost to do nothing! Ok, you will process slowly the data when they will be there but, it's a tradeoff.
Create Cloud Function on the topic, or a Push Subscription to call a HTTP triggered Cloud Functions
You can also handle request concurrently with Cloud Run. Cloud Run can handle up to 250 requests concurrently (in preview), and because you will wait a lot, it's perfectly suitable. If you need more CPU and memory, you can increase these value to 4CPU and 8Gb of memory. It's my preferred solution.
Bulk processing is possible if you are able to easily manage multi-cpu multi-(light)thread development. It's easy in Go. Concurrency in Node is also easy (await/async) but I don't know if it's multi-cpu capable or only single-cpu. Anyway, the principle is the following
Create a pull subscription on PubSub topic
Create a Cloud Run (better for multi-cpu, but also work with App Engine or Cloud Functions) that will listen the pull subscription for a while (let's say 10 minutes)
For each message pulled, an async process is performed: get the data/attribute, make the call to BigQuery, ack the message
After the timeout of the pull connexion, close the message listening, finish the current message processing and exit gracefully (return 200 HTTP code)
Create a Cloud Scheduler that call every 10 minutes the Cloud Run service. Set the timeout to 15 minutes and discard retries.
Deploy the Cloud Run service with a timeout of 15 minutes.
This solution offers a better message throughput processing (you can process more than 250 message per Cloud Run service), but don't have a real advantage because you are limited by the API call latency.
EDIT 1
Code sample
// For pubsunb triggered function
exports.logMessageTopic = (message, context) => {
console.log("Message Content")
console.log(Buffer.from(message.data, 'base64').toString())
console.log("Attribute list")
for (let key in message.attributes) {
console.log(key + " -> " + message.attributes[key]);
};
};
// For push subscription
exports.logMessagePush = (req, res) => {
console.log("Message Content")
console.log(Buffer.from(req.body.message.data, 'base64').toString())
console.log("Attribute list")
for (let key in req.body.message.attributes) {
console.log(key + " -> " + req.body.message.attributes[key]);
};
};
I want to run the same request multi times with different pre-request scripts? Any idea how can I do it without using the Data Driven (CSV) test?
Eg., I have to run the below GET url multiple times (every 2 minutes) but whenever I run this, I need to have a different pre request tests!
{{url}}/legacy/COL
enter image description here
Onetime operation:
If you want to send request 10 times (including first request 11) , then create two environment variables that contains the count. you can create the variables by simply copy pasting the below two lines in pre-request or test script ( remove all other code).
pm.environment.set("repeat",10);
pm.environment.set("repeat",10);
Once the variables are added remove the above lines from script.
Now in test script:
we can sendrequest multiple time by using pm.sendrequest or pm.setNextrequest. Here the example shows calling same request 10 more times using pm.setNextRequest.
The delay of 2mins or 3 mins can be set using the setTimeout javascript function which waits the mentioned time (here 3 seconds ) before executing the code inside that. so the setNextrequest will executed only after 3 sec in this case you can change it to 2 mins.
let repeatTemp = pm.environment.get("repeatTemp");
if (repeatTemp === 0) {
pm.environment.set("repeatTemp", pm.environment.get("repeat"));
} else {
let repeatTemp = pm.environment.get("repeatTemp")
let increment = pm.environment.get("increment")===0?15:pm.environment.get("increment")+5
pm.environment.set("increment",increment)
pm.environment.set("repeatTemp", repeatTemp-1);
setTimeout(function () { postman.setNextRequest("something") }, 3000);
}
so if your request name is "yourrequestname" then it will send this request 1+10 times
Pre-request script:
in your format you mentioned yyyy-mm which is wrong mm stands for minutes not month for year-month you have to give capital YYYY-MM
let repeatTemp = pm.environment.get("repeatTemp");
let repeat = pm.environment.get("repeat");
if (repeatTemp===repeat) {
pm.environment.set("increment", 0)
}
let moment = require('moment')
pm.environment.set('estimatedTimeArrival', moment().add(30 + pm.environment.get("increment"), 'minutes').format("YYYY-MM-DDThh:mm:ss"));
pm.environment.set('estimatedTimeDeparture', moment().add(2, 'hours').format("YYYY-MM-DDThh:mm:ss"));
pm.environment.set('scheduledTimeArrival', moment().add(10, 'minutes').format("YYYY-MM-DDThh:mm:ss"));
console.log(pm.environment.get('increment'))
console.log(pm.environment.get('estimatedTimeArrival'))
output:
I'm working with RabbitMQ instances hosted at CloudAMQP. I'm calling the management API to get detailed queue statistics. About 1 in 10 calls to the API return invalid numbers.
The endpoint is /api/queues/[vhost]/[queue]?msg_rates_age=600&msg_rates_incr=30. I'm looking for average message rates at 30 second increments over a 10 minute span of time. Usually that returns valid data for the stats I'm interested in, e.g.
{
"messages": 16,
"consumers": 30,
"message_stats": {
"ack_details": {
"avg_rate": 441
},
"publish_details": {
"avg_rate": 441
}
}
}
But sometimes I get incorrect results for one or both "avg_rate" values, often 714676 or higher. If I then wait 15 seconds and call the same API again the numbers go back down to normal. There's no way the average over 10 minutes jumps by a multiple of 200 and then comes back down seconds later.
I haven't been able to reproduce the issue with a local install, only in production where the queue is always very busy. The data displayed on the admin web page always looks correct. Is there some other way to get the same stats accurately like the UI?