I'm using Firebase Remote Config with Firebase A/B Testing on iOS.
I see a value received from Remote Config sometimes reset to default value.
I think, activated config values does not delete even if server cache on the app has expired.
Is there any situation that activated values are back to the default value?
In-App: Default Value A set.
fetch -> activate
Got B from the server.
Leave apps.
Several hours later, I come back to the app, it seems the value is reset to A.
fetch and activated a strategy
The app activates remote config values once at launch time.
https://firebase.googleblog.com/2017/01/firebase-remote-config-loading.html
Strategy #3: Load values for next time
When your user starts up your app, you immediately call activateFetched(). This will apply any old values you've previously fetched from the cloud. And then your user can immediately start interacting with your app. In the meantime, you kick off an asynchronous fetch() call to fetch new values from the cloud. And in the completion handler for this call… you do nothing. Heck, you don't even need to add a completion handler in the first place. Those values you fetched from the cloud will remain stored locally on the device until your user calls activateFetched the next time they start your app.
ABTesting Settings
target user: 100% of the app
variant-key -> SOME_KEY
Control Group: 50% -> value = A
Variant B: 50% -> value = B
Pods versions from Podfile.lock:
- FirebaseABTesting (2.0.0):
- FirebaseRemoteConfig (3.1.0):
How to set defaults, get values
Default Value is:
RemoteConfig.remoteConfig().setDefaults(["SOME_KEY": "A"])
To get Value from Remote Config:
let value = RemoteConfig.remoteConfig().configValue(forKey: "SOME_KEY")
App Launch Sequences
At first app launch
activateFetched()
got value A(=default).
There is no fetched value yet, activateFetched has no effect.
then fetch.
next time app launch
activateFetched()
got value B (if the user is selected ABTestring's value 'B')
then fetch.
next time app launch
activateFetched()
got value A (this is the issue)
then fetch.
In the above situation, if the app fetched and activated value B,
the value is persisted in activated values cache and
the cached value doesn't reset to A I thought.
Is the assumption right?
Addtional Info
When the app got B from configValue(forKey: "SOME_KEY")
then remoteConfig.allKeys(from: .remote, namespace: NamespaceGoogleMobilePlatform) returns ["SOME_KEY"].
But when the app got A back from 'B' (the last situation in above launch sequence),
then remoteConfig.allKeys(from: .remote, namespace: NamespaceGoogleMobilePlatform) returns empty.
Related
We are using MongoDB Realm in our app.
The first time the user is connected to the app, the ProgressNotifcation callback is triggered correctly, and it will work and trigger whenever a new download is coming.
Even if no download is pending, the ProgressNotification callback will be triggered (the Progress object pass in the callback will contain values from the last download) at least once(when creating it). I supposed this is due to the fact that we are downloading the first data set of the user.
But after killing the app and launching it again, the ProgressNotification callback is not triggered anymore until new data are received by the app. And from this point, the callback will be called every time we need it.
It seems that now, the framework needs a first download since the app is launch to make ProgressNotification callback to be triggered every time we need it.
This was working in the previous version of Realm (5.X.X). We just finished the migration to Realm 10 and discover this issue.
I am a bit stuck here, do not know if this is an intended change or a bug on my part. But I am pretty sure this was working in the previous version of the SDK.
Can anyone help me with this? Thanks
Note: this is no more working in both mode : .forCurrentlyOutstandingWork and .reportIndefinitely
Example
self.token = syncSession.addProgressNotification(for: .download, mode: .forCurrentlyOutstandingWork) { progress in
.......Some code........ <- this part of the code is not triggered anymore
}
EDIT - 21/12/2020
For clarification, the token returned contains a value and the .invalidate is not being called.
There is no error in the session and any new download is triggering the callback. After an initial download, everything works as expected. This means that when I add a progressNotifcation later on, the callback is triggered immediately with the progress of the previous download. But if there is not an initial download, the callback is never called.
For the scope, this method is actually in the custom publisher that I created and it is not deallocated.
Realm 10.5.0
iOS 14.3
I'm trying to configure Firebase A/B experiment only for new users of my app.
What I did:
1) I set custom_first_open_time user param on the app first launch equal to timestamp in millis from epoch
2) I created a new experiment, set custom_first_open_time > 1581944923450 in the targeting section
3) I used 1 of 10 remote config params for the experiment. Once I started, all users stopped obtaining any remote config param and inside the app was used params set as default in code (inside the app). None of 10 params obtained in the app, though I change only 1 in A/B
Why using value of this param brakes the whole remote config?
Why it doesn't work as I expect?
Any help appreciated!
The problem was because of using millis from epoch and looks like firebase couldn't compare so large numbers. Using just seconds solved the problem
I created a serverless function that performs that Firebase Token Validation.
Everything works as intended. Except, I have I get errors on subsequent calls to initialize my app that the default app already exists (same container). This raises some questions.
If my serverless infrastructure was to spin up multiple concurrent containers, each working to initialize the app. Would this also cause this error? That the app is initiailized elsewhere? Or is this error isolated to local instances?
If its the latter, If I provide a named app based on the container it is spun up in, is there a firebase limit to the maximum number of apps that can be initialized at once?
This is how I am initializing the app now:
cred = credentials.Certificate(SERVICE)
firebase_admin.initialize_app(cred)
I could do this but am not sure about firebase app limits or concurrent initializations (cant find any specifics in docs):
cred = credentials.Certificate(SERVICE)
firebase_admin.initialize_app(cred, 'APP-NAME-[CONTAINERID]')
Or, should I just re-write this using my own JWT Decoder and grabbing the public keys from google?
And here is the full error:
Error occurred setting firebase credentials: The default Firebase app already exists. This means you called initialize_app() more than once without providing an app name as the second argument. In most cases you only need to call initialize_app() once. But if you do want to initialize multiple apps, pass a second argument to initialize_app() to give each app a unique name.
UPDATE: AWS Lambda, Python.
I am going to test out with the following, to prevent re-initializing the app within the same container on warm function executions and move forward with the assumption that there are no API limits on performing auth.validate_id_token() and that this won't conflict with concurrent container executions. Ill report back if it tests out differently.
try:
firebase_admin.get_app()
logger.info('firebase already intialized.')
except ValueError as e:
logger.info('firebase not initialized. initialize.')
cred = credentials.Certificate(SERVICE)
firebase_admin.initialize_app(cred)
I will probably still migrate to another JWT validation to reduce function size (since I already have a jwt library for my own app use) and migrate away from relying on Firebase API to decode it.
If you get an error when initializing the admin SDK that says the default app already exists, that just means you're trying to init the admin SDK twice in the same process. Obviously, don't do that. If you init once and only once per process, you will never see this error.
You will have to take some care to only call the init method once per server instance. It's not clear exactly what you're doing from the code you've shown. I don't know about python, but with node, you can init once in a global context without problems. If you need to init during a function execution, you should have some flag to check that ensures the default Firebase app hasn't already been initialized, and init only conditionally based on that flag.
I have clients connecting to the database with javascript.
I also have code running on my server and I'm trying to do a transaction following example as shown here:
https://firebase.google.com/docs/database/server/save-data#section-transactions
Here's a simplified structure of my data
users:
userguid
resource : "room1"
printer : "printer1"
resources
rooms
room1
printers
printer1
counter : 15
The web client would write a request to their own node under "users".
The server is watching for those request and updates the counter for that resource.
If i have the transaction watching for child added I get null for counter so I can't increment the number. If I also watch for child modified the I will get the correct counter value.
I understand from the documentation that the value in transaction can be null but I'm not sure how I can fix my use case to do what I need.
Basically I don't want the client touching the counter, I want the server to read and update that value.
I've gone thru this post
Firebase runTransaction not working
but I'm not clear on how to structure my code to deal with this.
I want to load test an enterprise Web application (which I did not build), using a Visual Studio 2010 Ultimate Load Test. I want each virtual user to log in at the beginning, and log out at the end of their run of random tests. I can properly configured the load test to do so. However, there is a complication. The session key is injected into the URL, like this:
http://ProductName/(S(ilv3lp2yhbqdyr2tbcj5mout))/System/Container.aspx
I converted the Visual Studio WebTests to coded tests, and then retrofit them with code that uses the session-specific URL. This works fine. What I need to do is persist this session encoded URL across the various tests that specific virtual user runs, starting with the login WebTest class, to the logout WebTest class.
The individual WebTest classes are capable of logging in and out at the beginning and end of each test. However, this is not an accurate representation of normal use. This application emulates a mainframe terminal, and never cuts the connection or session between Web browser requests. Each session is one long, interactive HTTP request, just like a mainframe terminal interacts with, for example, an IBM AS400. Usert typically log in to the mainframe at the beginning of day, and (should) log out at the end of day. Likewise, this Web application maintains the HTTP request until the user logs out, or the IIS session timeout occurs. Therefore, it is important I keep the same session in the URL, between all tests, to ensure memory leaks and other nasty bugs don't accumulating.
Please share your thoughts!
Problem 1: persist the session id across test iterations
You can store data in the 'user context' which is persistent across test iterations. It is found in the WebTestContext having the name '$LoadTestUserContext'. (But note that this context parameter only appears in load test runs, not in standalone web test runs)
// within WebTestPlugin.PreRequest() or MyExtractionRule.Extract()
// e is the corresponding eventargs object...
LoadTestUserContext userContext = (LoadTestUserContext)e.WebTest.Context["$LoadTestUserContext"];
...
// setting the value in the user context (i.e. in the extraction rule)
userContext["sessionId"] = "(extracted session id)";
...
// getting the value from the user context (i.e. in WebTestPlugin PreWebTest event)
e.WebTest.Context["sessionId"] = userContext["sessionId"];
You'll have to add a WebTestPlugin (that fetches the value from the user context into the web test context) to all of your web tests to make the value available across all tests.
Problem 2: Login/Logout only at start and end of load test
extract the login and logout functionality into their own separate tests (remember that the logout test also needs the WebTestPlugin that fetches the stored sessionId)
in the Load Test, the Edit Test Mix dialog lets you specify an Initialize and Terminate test: set these to the Login and Logout tests you just created
in the Load Test Scenario, set "Percentage of New Users" to 0.
Some additional explanation of the "Percentage of New Users" setting
The "Percentage of New Users" setting is poorly named and does not indicate its full behaviour.
When a "New User" starts a test iteration, it takes a new $WebTestUserId (and gets a new fresh user context, which you don't want)
When a non-"New User" starts a test iteration, it keeps the same old $WebTestUserId (and the old user context, which you do want)
So far so good. But the unexpected part is this:
Each "New User" executes the following during a load test:
Initialize > web test iteration > Terminate
A non-"New User" executes the following for the entire duration of the load test:
Initialize > iteration1 > iteration2 > ... > iterationN > Terminate
In other words, "New Users" are constantly logging in and out (which you don't want). Non-"New Users" only login and logout once in the entire load test, and continually run test iterations for the duration (which you do want).