pretty

Thursday, 31 January 2019

GoScores: leaderboard on Google Cloud


Simple Leaderboard server, written in Go language and hosted on Google Cloud. Source (Github).

Sample app that uses the leaderboard: Buildris on Google Play


Update: Migrating to Go 1.16 on Google Cloud.

Google Cloud no longer supports Go 1.11 runtime, the migration guide from Google is available.

Appengine google.golang.org/appengine/* packages were removed and google cloud cloud.google.com/go/* packages have to be used instead (or Go standard library packages were applicable).

For example:
google.golang.org/appengine/datastore -> cloud.google.com/go/datastore (from Google cloud library) google.golang.org/appengine/log -> log (from Go standard library package)

Sample diff of migration for GoScores app from 1.11 to 1.16, that uses Google Cloud datastore.

To highlight other migration changes:
  • Port should now be set explicitly
  • Data store API was modified, for example, query.GetAll(() is now dsClient.GetAll().
  • Some functions calls changed, for example RunInTransaction() no longer accepts nil for TransactionOptions. Passing nil would result in 503 Server Error and in logs: “panic serving … nil TransactionOption goroutine [running]:”

To test locally:
  • Credentials should be locally available, run export with a path to the file with key:
    export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/service-account-file.json"
    Key is available for download in Cloud Console, IAM and Admin -> Service accounts -> Keys tab. https://cloud.google.com/docs/authentication/production
  • go run scores.go
  • check GET response on localhost:8080


To deploy:
Inside app dir call (given google-cloud-sdk directory is one level up) ../google-cloud-sdk/bin/gcloud app deploy

-----
Full logs of app execution and errors are available in Logs Explorer: https://console.cloud.google.com/logs

Sunday, 3 June 2018

Managing long running task in React Native


In React Native network request is normally done with non-blocking method like fetch(). On receiving result redux-thunk middleware can be used to dispatch the new state.

Now there is a question: how to make our own non-blocking method for performing lengthy computation. This can be done using 3rd-party native extensions that introduce threading or WebWorkers to react native, or writing our own extension. There is also a workaround with creating a WebView and moving the long running function there.

There is a lighter solution, that would block the JS thread, but it allows for showing the progress indicator. Assume I want to perform an action that takes a few seconds, but first shows a progress indicator.

This action would block JS thread:
export const getData = () => {
   for (i = 0; i < 5000; i++) {
       console.log(i)
   }
   return { type: DATA_READY } 
}


To show the progress let us switch from 'return' to redux-thunk 'dispatch', and add additional state change before the computation. The flag 'loading' would be used to show progress bar in view.
export const getData = () => {
  return (dispatch) => {
    dispatch({type: DATA_CALCULATION loading: true})

    for (i = 0; i < 5000; i++) {
       console.log(i)
    }

    dispatch( { type: DATA_READY loading: false })
  }
}


The progress would not be shown despite the new state would have 'loading:true' set before computation. This happens because getData() action blocks for quite some time after the first dispatch(). This prevent the view from receiving its render() call. To make the view render before the blocking code we should move the lengthy cycle into the requestAnimationFrame() callback:
export const getData = () => {
  return (dispatch) => {
    dispatch({type: DATA_CALCULATION loading: true})

    requestAnimationFrame(() => {

       for (i = 0; i < 5000; i++) {
          console.log(i)
       }

       dispatch( { type: DATA_READY loading: false })
   })
  }
}


The requestAnimationFrame() callback is invoked before next repaint, and view now gets its render() call before the 'for' loop being launched. Progress indicator is shown and then it gets updated on main (UI) thread, while JS thread would be blocked.

Saturday, 5 May 2018

Handling exceptions thrown from ActivityThread in Android


Sometimes it is desired to prevent the default exception handler from terminating application. This may be done via setting custom default uncaught exception handler.

What happens if the caught exception is thrown from ActivityThread? See Android/Sdk/sources/android-26/android/app/ActivityThread.java for the source. When exception is thrown from ActivityThread the Looper.loop() cycle invoked from ActivityThread.main() method terminates. As the exception is caught by custom default exception handler, it does not instruct application to finish. However, application becomes frozen. Main looper no longer processes new messages.

To make application run again, the main looper needs to be revived. This can be done inside the custom exception handler:
    private void setOnErrorFailedExceptionHandler() {
        android.os.Handler handler = new android.os.Handler(Looper.getMainLooper());
        Thread.UncaughtExceptionHandler uncaughtExceptionHandler =
                                        Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler((t, e) -> {

            if (e instanceof AndroidRuntimeException 
                        /*&& e is a specific exception that needs treatment*/) {
                android.util.Log.e("error", "DefaultUncaughtExceptionHandler", e);
                Looper.loop() // Revive main looper 
            } else if (uncaughtExceptionHandler != null) {
                // All other exceptions should be treated by default
                uncaughtExceptionHandler.uncaughtException(t, e); 
            }
        });
    }


Some edge cases may be solved with this trick. For example, take the introduction of new exception in Android O "android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()". The stacktrace for this exception shows that is is thrown from ActivityThread:
"android.app.ActivityThread$H.handleMessage(ActivityThread.java:1775)"
"android.os.Handler.dispatchMessage(Handler.java:105)"
"android.os.Looper.loop(Looper.java:164)"
"android.app.ActivityThread.main(ActivityThread.java:6541)"
"java.lang.reflect.Method.invoke(Native Method)"
"com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)"
"com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)"


The android.app.RemoteServiceException is a private exception, that subclasses AndroidRuntimeException.

This exception is meant to terminate application, so that the developers should follow the new foreground service rules. If time span between the startForegroundService() and setForegorund() call in Service.onCreate() is longer than ANR period, then this exception is thrown. It was not designed to be caught. There are a few catches though, when terminating application with a crash is undesired, given that "startForegroundService() -> startForeground()" rule is already implemented.

1. During debug sessions this exception fires quite often, because of slower emulator - or just the breakpoints being hit.
2. When released, the actual user device may lag in the very unfortunate moment between those calls, and app will be hit with the crash.

Especially in the second case it would be much better to retry the service start, or opt it to be started later, instead of crashing app altogether. Catching such exception and reviving main loop afterwards is possible with this approach.