I'm trying to use relevantDate to refine when the passes for my app are shown.
The relevantDate options I know about are: specify a start and end time on a single day, or specify a single time which seems to show the pass in the lock screen for about a four-hour window in either direction (!), at least for the "generic" pass type.
It seems like there ought to be a way to specify, e.g., for a coupon, that it should be shown on the lock screen when they're in the store for the next two weeks, at which point it should expire. Is there? If so, what is it?
Sorry, there's not currently a way to do this.
Relevance is a cooperative effort between you and the system. Your pass gives a point in time (the relevant date) and/or a point in space (the relevant locations). There's no API to provide a duration or a region. The system decides what radius to use around that location and what window of time to use around the date. There is some documentation for the relevant locations in the Passbook guide but the time window is not documented. In practice, the time window is on the order of 4-8 hours, depending on the pass style.
You should go on Apple's bug report page and file an enhancement request, describing how it would add value to your coupons to be relevant for multiple days.
Although not quite what you are looking for, you could send a push update to remove the locations after the promotion period ends.
If you have a promotion that is valid in a particular store, then you could use locations with relevantText appropriate for the promotion period E.g. 20% Off, Ends Jan 20. Once the promotion ends, you then send a push with no locations (or replace with a new offer).
The relevantDate key is not supported by the coupon or storeCard pass types and there is no way to specify a custom lock screen message for a time based alert, so personally I prefer to use location alerts whenever a location is known. The exception would be when it makes sense to remind the user a few hours beforehand (E.g. for a dental appointment or scheduled personal training session).
Related
I am designing a basket abandoning system for an Ecommerce company. The system will send a message to a user based on the below rules:
There is no interaction by the user on the site for 30 minutes.
Has added more than $50 worth of products to the basket.
Has not yet completed a transaction.
I use Google Cloud Dataflow to process the data and decide if a message should be sent. I have couple of options in below:
Use a Sliding window with a duration of 30 minutes.
A global window with a time based trigger with a delay of 30 minutes.
I think Sliding Window might work here. But my question is, can there be a solution based on using a global window with a processing time based trigger and a delay for this usecase?
As far as i understand the triggers based on Apache Beam documentation =>
Triggers allow Beam to emit early results, before a given window is closed. For example, emitting after a certain amount of time elapses, or after a certain number of elements arrives.
Triggers allow processing late data by triggering after the event time watermark passes the end of the window.
So, for my use case and as per the above trigger concepts, i don't think the trigger can be triggered after a set delay for each and every user (It is mentioned in above - can emit only after a certain number of elements it is mentioned above, but not sure if that could be 1). Can you confirm?
Both answers 1 - Sliding Windows and 2 - Global Window are incorrect
Sliding windows is not correct because - assuming there is one key per user, a message will be sent 30 minutes after they first started browsing even if they are still browsing
Global Windows is not correct because - it will cause messages to be sent out every 30 minutes to all users regardless of where they are in their current session
Even Fixed Windows would be incorrect in this case, because assuming there is one key per user, a message will be sent every 30 minutes
Correct answer would be - Use a session window with a gap duration of 30 minutes
This is correct because it will send a message per user after that user is inactive for 30 minutes
I think that sliding window is the correct approach from what you described, and I don't think you can solve this with trigger+delay. If event time sliding windowing makes sense from your business logic perspective, try to use it first, that's what it's for.
My understanding is that while you can use a trigger to produce early results, it is not guaranteed to fire at specific (server/processing) time or with exact number of elements (received so far for the window). The trigger condition enables/unblocks the runner to emit the window contents but it doesn't force it to do so.
In case of event time this makes sense, as it doesn't matter when the event arrives or when the trigger fires, because if the element has a timestamp within a window, then it will be assigned to the correct window no matter when it arrives. And when the trigger will fire for the window, the element will be guaranteed to be in that window if it has arrived.
With processing time you can't do this. If event arrives late, it will be accounted for at that time, and will be emitted next time the trigger fires, basically. And because the trigger doesn't guarantee the exact moment it fires you can potentially end up with unexpected data belonging to unexpected emitted panes. It is useful to get the early results in general but I am not sure if you can reason about windowing based on that.
Also, trigger delay only adds a fire delay (e.g. if it was supposed to fire at 12pm, not it will fire at 12.05pm) but it doesn't allow you to reliably stagger multiple trigger firings so that it goes off at specific intervals.
You can look at the design doc for triggers here: https://s.apache.org/beam-triggers , and possibly lateness doc may be relevant as well: https://s.apache.org/beam-lateness
Other docs can be found here, if you are interested: https://beam.apache.org/contribute/design-documents/ .
Update:
Rui pointed that this use case can be more complicated and probably not easily solvable by sliding windows. Maybe it's worth looking into session windows or manual logic on top of keys+state+timers
I find state[1] and timer[2] doc of Apache Beam, which should be able to handle this specific use case without using processing time trigger in global window.
Assuming the incoming data are events of users' actions, and each event(action) can be keyed by user_id.
The nice property that state and timer have is on per key and window basis. So you can accumulate state for each user_id and the state is amount of money in cart in this case. Timer can be set at the first time when amount in cart exceeds $50, and timer can be reset when user still have shopping actions within 30 mins in processing time.
Assume transaction completion is also a user_id keyed event. When an transaction completion event is seen, timer can be deleted[3].
update:
This idea is completely on processing time domain so it will have false alarm messages depending on lateness problem in system. So the question is how to improve this idea to event time domain so we have less false alarm. One possibility is event time based timer[4]. I am not clear what does event time based timer mean at this moment.
[1] https://beam.apache.org/blog/2017/02/13/stateful-processing.html
[2] https://docs.google.com/document/d/1zf9TxIOsZf_fz86TGaiAQqdNI5OO7Sc6qFsxZlBAMiA/edit#
[3] https://github.com/apache/beam/blob/master/sdks/java/core/src/main/java/org/apache/beam/sdk/state/Timers.java#L45
[4] https://github.com/apache/beam/blob/master/sdks/java/core/src/main/java/org/apache/beam/sdk/state/TimeDomain.java#L33
I want my app to have a subscription service and the way I see it is by keeping timeIntervalSince1970 as an "until" date. But that is easily avoidable if the user changes system's current time. Is there any better way to track that in offline mode?
take a look at this post1, it explain how to measure passed time, independent of clock and time zone changes.
you also take a look at this post2, it explain how detect device time change only when it is changed manually
Let me know if this helps you :)
I am working on a app that relies heavily on monitoring user visits in possibly multiple regions / areas. I am currently experimenting with region monitoring which works pretty well, however, the location callback is not as accurate as I want it to be. I have seen CLVisit, but the documentation out there doesnt explain it very well, especially its use.
I think you are misunderstanding the concept of CLVisits. There is actually no Visit object that you need to create. The CLLocationManager delegate method is triggered by the algorithm that apple has determined (see wwdc lecture for more info). This is explained in the CLLocationManager documentation...
Getting the Visited Locations
In iOS, the visits service provides an alternative to the significant location change service for apps that need location information about interesting places that the user visited. For example, if the user is in one location for an extended period of time, the service might generate an event when the user arrives at that location and another when the user leaves that location. The service is intended for apps that might already be using the significant location change service and want an even lower power way to do so. You would not use this service to create navigation apps or apps that rely on regular location updates.
To begin the delivery of visit-related events, assign a delegate to the location manager object and call its startMonitoringVisits method. As the location manager generates visit events, it delivers that information to its delegate’s locationManager:didVisit: method. The event data delivered to your delegate includes only the information that occurred after you started the delivery of events. In other words, if you start the delivery of events after the user arrived at an interesting location, the event delivered by the system when the user departed that location would not reflect the actual arrival time. If the system terminates your app, this service relaunches it when new visit events are ready to be delivered.
That said if you look at this article from NSHipster, it references some current issues with CLVists (for iOS 8.1). It essentially goes on to say that if you want infrastructure that extremely precise don't use CLVisit. Seems like you're doing it right (for now at least).
CLVisit is, as of iOS 8.1, not all that precise. While start and end times are
generally accurate within a minute or two, lines get blurred at the edges of
what is and what is not a visit. Ducking into a corner coffee shop for a minute
might not trigger a visit, but waiting at a particularly long traffic light
might. It’s likely that Apple will improve the quality of visit detection in
future OS upgrades, but for now you might want to hold off on relying on CLVisit
in favor of your own visit detection for use cases where it’s vital your data is
as accurate as it can be.
I want to deploy managed iOS devices to employees of the company, and the app they will use will timestamp data that will be recorded locally, then forwarded. I need those timestamps to be correct, so I must prevent the user from adjusting the time on the device, recording a value, then resetting the date and time. Date and time will be configured to come from the network automatically, but the device may not have network connectivity at all times (otherwise I would just read network time every time a data value is recorded). I haven't seen an option in Apple Configurator to prevent changing the date and time, so is there some other way to do this?
You won't be able to prevent a user either changing their clock or just hitting your API directly as other commentators have posted. These are two separate issues and can be solved by having a local time that you control on the device and by generating a hashed key of what you send to the server.
Local Time on Device:
To start, make an API call when you start the app which sends back a timestamp from the server; this is your 'actual time'. Now store this on the device and run a timer which uses a phone uptime function (not mach_absolute_time() or CACurrentMediaTime() - these get weird when your phone is in standby mode) and a bit of math to increase that actual time every second. I've written an article on how I did this for one of my apps at (be sure to read the follow up as the original article used CACurrentMediaTime() but that has some bugs). You can periodically make that initial API call (i.e. if the phone goes into the background and comes back again) to make sure that everything is staying accurate but the time should always be correct so long as you don't restart the phone (which should prompt an API call when you next open the app to update the time).
Securing the API:
You now have a guaranteed* accurate time on your device but you still have an issue in that somebody could send the wrong time to your API directly (i.e. not from your device). To counteract this, I would use some form of salt/hash with the data you are sending similar to OAuth. For example, take all of the parameters you are sending, join them together and hash them with a salt only you know and send that generated key as an extra parameter. On your server, you know the hash you are using and the salt so you can rebuild that key and check it with the one that was sent; if they don't match, somebody is trying to play with your timestamp.
*Caveat: A skilled attacked could hi-jack the connection so that any calls to example.com/api/timestamp come from a different machine they have set up which returns the time they want so that the phone is given the wrong time as the starting base. There are ways to prevent this (obfuscation, pairing it with other data, encryption) but that becomes a very open-ended question very quickly so best asked elsewhere. A combination of the above plus a monitor to notice weird times might be the best thing.
There doesn't appear to be any way to accomplish what you're asking for. There doesn't seem to be a way to stop the user from being able to change the time. But beyond that, even if you could prevent them from changing the time, they could let their device battery die, then plug it in and turn it on where they don't have a net connection, and their clock will be wrong until it has a chance to set itself over a network. So even preventing them from changing the time won't guarantee accuracy.
What you could do is require a network connection to record values, so that you can verify the time on a server. If you must allow it to work without a net connection, you could at least always log the current time when the app is brought up and note if the time ever seems to go backwards. You'll know something is up if the timestamp suddenly is earlier than the previous timestamp. You could also do this check perhaps only when they try to record a value. If they record a value that has a timestamp earlier than any previous recorded value, you could reject it, or log the event so that the person can be questioned about it at a later time.
This is also one of those cases where maybe you just have to trust the user not to do this, because there doesn't seem to be a perfect solution to this.
The first thing to note is that the user will always be able to forge messages to your server in order to create incorrect records.
But there are some useful things you can use to at least notice problems. Most of the time the best way to secure this kind of system is to focus on detection, and then publicly discipline anyone who has gone out of their way to circumvent policy. Strong locks are meaningless unless there's a cop who's eventually going to show up and stop you.
Of course you should first assume that any time mistakes are accidental. But just publicly "noticing" that someone's device seems to be "misbehaving" is often enough to make bad behaviors go away.
So what can you do? The first thing is to note the timestamps of things when they show up at the server. Timestamps should always move forward in time. So if you've already seen records from a device for Monday, you should not later receive records for the previous Sunday. The same should be true for your app. You can keep track of when you are terminated in NSUserDefaults (as well as posting this information to the server). You should not generally wake up in the past. If you do, complain to your server.
Watch for UIApplicationSignificantTimeChangeNotification. I believe you'll receive it if the time is manually changed (you'll receive it in several other cases as well, most of them benign). Watch for time moving significantly backwards. Complain to your server.
Pay attention to mach_absolute_time(). This is the time since the device was booted and is not otherwise modifiable by the user without jailbreaking. It's useful for distinguishing between reboots and other events. It's in a weird time unit, but it can be converted to human time as described in QA1398. If the mach time difference is more than an hour greater than the wall clock time, something is weird (DST changes can cause 1 hour). Complain to your sever.
All of these things could be benign. A human will need to investigate and make a decision.
None of these things will ensure that your records are correct if there is a dedicated and skilled attacker involved. As I said, a dedicated and skilled attacker could just send you fake messages. But these things, coupled with monitoring and disciplinary action, make it dangerous for insiders to even experiment with how to beat the system.
You cannot prevent the user from changing time.
Even the time of an Location is adjusted by Apple, and not a real GPS time.
You could look at mach kernel time, which is a relative time.
Compare that to the time when having last network connection.
But this all sounds not reliable.
I'm looking for guidance on how to architect an elegant solution to what has become a bit of a thorny problem. Although I am using Ruby (and Rails) I think my problem is largely an architectural one, though my choice of language obviously has an impact in terms of suggestions involving libraries, etc., so the language remains relevant.
Anyway, in a nutshell: my application contains objects representing memberships, belonging to people who are members of fitness facilities. Memberships contain a series of recurring payments. Some memberships automatically renew at the end of their term, while others do not.
So for example, you may have a membership that is for an initial period of one year, and then renews month-to-month after that. In the application, creating a membership of this kind causes 12 recurring payments to be created. When the last month expires, so does the membership. A daily cron task is responsible for causing memberships to expire based on completed payments. If the membership is set to automatically renew, the same cron task will renew the membership.
You may also have memberships that have no initial term and simply run month-to-month or week-to-week. These work in a similar manner, minus the initial payment scheduling.
So far so good. What makes things complicated are the additional requirements:
administrators can "freeze" memberships (put them on hold), for specific durations, after which they automatically reactivate (e.g. to represent people who go away on vacation for a set period of time). I can choose to freeze a membership right now and have it reactivate later, or I can choose to schedule a freeze by setting the freeze date at some point in the future, as well as the reactivation date (note: there is always a reactivation date, which makes things a bit easier).
administrators can cancel memberships, either right now, or by setting a cancellation to occur in the future. (Future cancellations are not yet built.)
administrators can refund memberships, which is like a cancellation except any past payments are refunded.
What makes these difficult to deal with is the effect on recurring payments. When you freeze a membership, the recurring payments must "stretch out" around the freeze period, so that the period of time that represents the freeze is not paid for. This is both conceptually and programmatically difficult to handle. Payments, for example, may extend for different periods (i.e. each payment for someone who pays every other week pays for two weeks of a membership), and the date of cancellation may be anywhere within the period the payment covers.
For the freezes, I have taken the approach where the membership object contains some dates, namely "freeze_on" and "thaw_on" to handle the freeze period. However, the client now wants future cancellations as well, and I have noticed some bugs with the freezing functionality, which leads me to believe I need to reconsider my approach.
I am considering changing things so that future events can be scheduled but have no effect on the recurring payments portion of the application. The idea would be to queue up particular events. For example, a freeze in the future would be accomplished by queuing up a freeze event on a particular date, and a thaw event on a subsequent date (these two events would be connected into a single "scheduled freeze" from the user's perspective). A future cancellation would be handled similarly.
This approach has some benefits, for example, if you wanted to cancel a future cancellation (that's the kind of annoying, tricky stuff I'm talking about), you could simply remove the scheduled cancellation from the events queue.
However, I have the nagging feeling that I may simply be jumping from the frying pan into the fire. I'm wondering if anyone could provide me with some guidance on this issue. Are there design patterns or existing architectural principles for this sort of problem that I can examine?
An additional thing to note is that recurring payments for memberships with scheduled terms (i.e. not month-to-month automatically renewing) must exist as database records that can be edited (moved in time, price adjusted), so using temporal expressions (as Martin Fowler suggests) is not appropriate for this problem, so far as I know. I realize that my proposed solution of an events queue would not display to the user the changes that would happen to any existing recurring payments, but I think I can live with that.
not a scanlife bar code, it's a qr code
toronto, give us your creative people
Edit: To respond to the two great suggestions below (the comment boxes don't allow nearly this level of detail):
Kris Robison:
Yes, the freeze period can be an arbitrary length, although in practice I imagine it would be rare for it to be less than two weeks. But any solution should work regardless of the length of the period.
Yes, the renewal date changes - it is pushed forward by the length of the freeze. So if the freeze is two weeks long, it pushes the payment forward by two weeks. To make things especially tricky, in some businesses, the payments can only be withdrawn on specific dates - for example, some clubs only process payments on the 1st and 15th of each month. So when dates are pushed around, for these clubs, they have to "snap" to a particular date.
Can you explain in more detail why these rules affect event queuing but not management of subscription payments?
I'm interested in your amortization table concept. That's basically exactly what I have built already - a year-long membership with monthly payments creates 12, with weekly it created 52 - and each of these have an amount, tax, etc., associated with them, along with a state machine that governs "pending", "paid", "failed", and "refunded" states.
The part I am struggling with is how this table responds to events. Right now, if you set a freeze, it affects the table immediately by changing the dates of the payments. Set a freeze in the middle of the table, and it pushes payments forward. That sounds effective, but it's actually quite complex and hard to manage. How would your amortization table idea improve this situation?
Arsen7:
This sounds like the event queue I proposed originally. It seems obvious to me that you've worked with stuff like this before (I was impressed by your error check on the processing date, this is a great idea and one I intend to implement ASAP) so I'm hoping that you can explain your suggestion in a little more detail.
Specifically, I'm wondering how your concept would deal with the recurring payment situation I've described in my original question, and in the comment that I just left on Kris Robison's answer. If I have set up a schedule of recurring payments for a given purchase, and a freeze event is scheduled for right in the middle of the payments, would the schedule of payments remain unchanged until the date of the freeze became the current date, at which time the freeze would be instituted and the payments would move forward?
This strikes me as perhaps a great way to simplify my application, but I am wondering how users would perceive it. How would I indicate to them that the schedule of payments they were looking at when a freeze has been scheduled is no longer an accurate schedule, but will change once the freeze takes place?
Is it acceptable to apply a scheme used by banking, where you process all account operations once a day?
Every object may have a set of (future) operations, like freeze periods, and every day the object has to make a simple decision, like: "should I expire today or not?"
The good part is, that such daily processing is very simple to program. Also a strange renewal rules (in case you would want them) are simple to design: "is it Friday? is it the last one in this month? If yes, mark me as renewed, add some amount to required payment, or do anything".
That would be very costly (in terms of computing power) to calculate the status dynamically, every time the object is asked. If you store the current "account", you only need more complex calculations when you want to predict future state.
Consider it a pseudo-code:
def process(day)
raise "Already processed or missed a day" unless day == last_processed_day + 1
check_expiration day
check_frozen day
check_anything day
#...
self.last_processed_day = day
self.save!
end
RESPONSE:
Specifically, I'm wondering how your concept would deal with the recurring payment situation I've described in my original question, and in the comment that I just left on Kris Robison's answer. If I have set up a schedule of recurring payments for a given purchase, and a freeze event is scheduled for right in the middle of the payments, would the schedule of payments remain unchanged until the date of the freeze became the current date, at which time the freeze would be instituted and the payments would move forward?
This strikes me as perhaps a great way to simplify my application, but I am wondering how users would perceive it. How would I indicate to them that the schedule of payments they were looking at when a freeze has been scheduled is no longer an accurate schedule, but will change once the freeze takes place?
The "daily processing" scheme helps you with providing quick responses for questions which require complex calculations.
You have three "groups": current state (asked often), history (almost never changing, asked relatively rarely), and future.
Your daily processing procedure is not constrained to only update "current" state. If some event is scheduled for the processed day, the procedure probably needs to add "history" records.
If your users will often ask questions about future (and as you said, they will), the "processing" may also create a kind of cache for these questions. For example: find (calculate) the next payment date, and write it in a helper table (a schedule).
The main thing you need to do is to decide which questions will be asked by users, and whether you are able to calculate the responses on-the-fly or you need to have the answer prepared.
In a bank (it varies, of course) if you ask about your current balance, they may give you the answer which was true at the beginning of the day. "Better" banks will tell you that you had X$ at the morning, but now there are also Y$ waiting for accounting.
So, if you put a freeze record into the event queue, you may call a method, which will update the schedule at once. The same procedure (or a very similar) will or may be called in the daily processing routine.
Couple of questions come to mind:
Can the freeze be for time periods less than a month?
If so, does the renewal date change? Or how does the monthly payment get applied for the partial month?
Those affect how your event queuing system may work, but don't ultimately change the management of subscription payments.
One way to address subscription issues is to create an amortization table of subscription payments. If they are paying monthly for a year, twelve payments are queued up in the table. A weekly customer may have 52 payments in the table for the same year. Each time the renewal date comes up, after checking whether a freeze is in place, apply the next payment.
The amortization table keeps track of which payments have been made. If an account cancels, unpaid rows are refunded. If an account freezes according to your event queue, no payment is applied and the table remains static until the account is thawed.
Reply
It sounds like you have the concept of renewal date built into the amortization table. I use the amortization table more as a queue, and keep just the next renewal date with the subscription.
If the renewal date is inherent with the amortization table, then yes, it would be complicated to make changes as things go along. However, the renewal date should only affect the day on which you check to see if another payment gets applied.
If you are preserving partial payments while a subscription is on hold, and if a hold can be for an unspecified period of time, having the duration value on the amortization table lets you push a partial payment back in the queue in a "credit" state with a duration equal to the remaining time left in the payment. That way when the account is thawed, that partial credit is applied first and you calculate the next renewal date from the remaining duration.
Use some form of ordered list to preserve payment order at this point. It also comes in handy should someone ever want to insert a renewal period's worth of credit for customer service reasons.