How can I run a webRequest on demand ("now") from a datafield?

Is there a way to execute a webRequest "now" in a datafield (given that there was no other webrequest in the last 5 minutes)?

I have a datafield, that does some web requests once in a while (from a background app). currently I can trigger this web request by:

if (needToDoTheRequest()) {
  var eventTime = Time.now().add(new Time.Duration(300));
  Background.registerForTemporalEvent(eventTime);
}
and in the serviceDelegate:
function onTemporalEvent() {
  fetchStatus();
}
This works, but it means that even when I do it for the 1st time it only lets me to trigger this 5 minutes in the future.
Then I realized that whenever I run the app (in the simulator at least) 1st the Background app will run, and then the foreground app. So I moved this code to the background app (no matter where: initialize/onStart/getServiceDelaget/ ServiceDelegate.initialize):

if (needToDoTheRequest()) {
  fetchStatus();
}
However what I see in the log is this:
Background: initialize
Background: onStart
Background: getServiceDelegate
Background: fetchStatus
Background: onStop

In other words the background app runs the http request, but it doesn't wait for the response, it just exits.
Is there a way to do the webRequest and wait for it, without triggering it with a temporalEvent 5 minutes into the future?
  • Not much code posted, but to do a makeWebRequest in the background, you call makeWebRequest, but don't call Background.exit() until you are in the onRecieve() call back.

    And you probably don't want the background to run unless the DF is running.  Set a flag in getServiceDelegate like this

        function getServiceDelegate(){
        	inBackground=true;
            return [new BgWu.WuServiceDelegate(false)];
        } 

    and then in onStop(), check that flag and do a deleteTemporalEvent is inBackground==false.

    onStop is called each time the background runs, but you only want to do the delete if onStop is called for the DF itself.

    The main app and the background have their own copy of variables like inBackground.

  • I only call Background.exit() in my webRequestCallback, and even so the 1st time when the Background app runs (right when I start to run the app in the sim) it just exits.

    I don't really understand the part you wrote about deleting the temporal event. Why would I delete it? My problem is that I want it to happen, but now, and not 5 minutes from now.

    I don't really care about the background running when the DF isn't running, in fact it's almost a feature for my use case: I check a license key that activates some features that are only enabled in pro version. So this would be a feature, that it can even check for the license before the DF runs, the only problem is that it has to same a generated uuid to the properties, and the background can't do that... It would be best for me if I could be able to do this:

    Foreground: initialize
    Background: initialize
    Background: onStart
    Background: getServiceDelegate
    Background: fetchStatus
    Background: onReceive
    Background: onStop
    Foreground: onStart

    Where all the Background stuff can be parallel to the foreground (onStart and later things), just I'd like the Background to start AFTER some code ran in the Foreground (in order to generate and save the UUID to the properties)

    All the other things you wrote are not relevant because I already have this:

    (:background)
    class MyApp extends Application.AppBase {
        (:background)
        private var app as AppDelegate;
    
        (:background, :typecheck(disableBackgroundCheck))
        function initialize() {
            app = getAppDelegate();
        }
    
        (:background, :typecheck(disableBackgroundCheck))
        hidden function getAppDelegate() as AppDelegate {
            var isBackground = isRunningInBackground();
            return (isBackground ? new BackgroundApp() : new ForegroundApp()) as AppDelegate;
        }
    
        // all the rest are delegated, i.e:
    
        (:background)
        public function onStop(state as Dictionary?) as Void {
            app.onStop(state);
        }
    }
    

  • put some println calls in your app around and in the background service.

    The backgound will trigger once or twice when an app starts (for onAppInstall()/onAppUpdate()) and not for a temporal event.  Are you sure that's not what you are seing?  (even if you don't have onAppInstall()/onAppUpdate() functions in your app base.)

    Doing the delete in onStop (but only for the main app), means next time the app starts, (as long as it's been more than 5 minutes) means the temporal event will run right away.

    And there are things like onBackgroundData can run before getInitialView

    Have you looked at this thread?  It started when backgrounding was first introduced:

    https://forums.garmin.com/developer/connect-iq/f/discussion/5287/very-simple-sample-of-a-watch-face-with-a-background-process

    and there is also this:

    https://developer.garmin.com/connect-iq/connect-iq-faq/how-do-i-create-a-connect-iq-background-service/

  • I do a getTemporalEventRegisteredTime first and if it's null you are free to schedule now. If not you have to add 5 minutes to the time you get back and use that to schedule the next run. I use 301 seconds just to be safe.

  • For something like a WF and weather, I usually use 15 minutes, and I set it up to just repeat every 15 minutes, as I want it to run even if I'm in the widget/glance loop.

    The background might not actually run every 15 minutes, if you are running a device app for example, but will run as soon as that device app terminates.

  • I need it to run on demand. I'll know when that is (according to the license expiration, but we're talking about days, not minutes) There's no point fetching it more often, but when I do want it I want it ASAP. So if I understand correctly then if I did not use Background.registerForTemporalEvent in the last 5 minutes, then I can call it with 0 and it'll be executed ASAP?

  • Hmm, it almost works for me too. The part that wasn't working does work now: the webRequest is made, and the onReceive callback in the background gets called with the response. But now it's not being passed to the foreground (this did work previously):

    (:background)
    public function onStatusResponse(responseCode as Number, data as Dictionary<Boolean or Number or Long or Float or Double or Char or String, Application.PropertyValueType> or String or Null) as Void {
        log("onStatusResponse: " + responseCode + ", " + data);
        Background.exit([STATUS, responseCode, data] as Array<Application.PropertyValueType>);
    }
    
    (:background)
    class MyApp {
        public function onBackgroundData(responseData as Application.PersistableType) as Void {
            //only runs in FG
        	log("onBackgroundData: " + responseData);
            app.onBackgroundData(responseData);
        }
    }
    

    onBackgroundData is never called now. (I see that Background: onStop is called when I call exit())

  • OK I think I found why. I added the logs Jim recommended:

    (:background)
    public function onAppUpdate() as Void {
        log("onAppUpdate");
        // Background.exit(null);
    }
    However I only added the log. So the background process was never shut down, and thus when later not everything related to background vs foreground worked. Adding the Background.exit(null) fixed it.