-
Notifications
You must be signed in to change notification settings - Fork 0
Advanced Topics
This page is dedicated to advanced topics regarding Objective-Cloud.
When you create a new cloud application using Objective-Cloud Connect a new Xcode project is created for you automatically. In order to understand some of the advanced topics it is important to understand the structure of the Xcode project.
Important: The created Xcode project is nothing special. In theory you can create Objective-Cloud compatible projects from scratch. The automatic creation is just there for your convenience.
The Xcode project contains a workspace (called CloudApp-WS.xcworkspace) and a project (called CloudApp.xcodeproj). By default you should always work the workspace. If you open up the workspace and select the CloudApp project in the project navigator you will see two targets:
- Service: At its core this target is simply a special kind of XPC service. The files Service.m and Service.h belong to that target. Class methods put in those files can be executed via HTTP and they are supposed to be stateless.
- CloudApp: This is a target that builds an application called CloudApp. CloudApp contains the XPC service.
If a request for the service comes in it will be routed to the service by the CloudApp application. You can add class methods to CloudApp.h and CloudApp.m and you can execute those methods as well.
If a request enters Objective-Cloud there are two cases which have to be handled. This all happens automatically behind your back but it is good to know the whole workflow. For the purpose of this chapter lets assume that your team prefix is 2ro0lf6gsticu and that you have a cloud application called com.objectivecloud.demos.
In Service.m you usually implement class methods that have little to no state. You can create global variables and write data disk but Objective-Cloud does not guarantee that those global variables and data written to disk will be valid/exist indefinitely. In addition your service can be started and stopped at any time. This makes the Service target the perfect place for your stateless business logic. If you want to address the service with a HTTP request you have to use the following URL:
invoke.objective-cloud.com/teams/2ro0lf6gsticu/apps/com.objectivecloud.demos/services/Service
This is a URL that addresses the service by using the above credentials. Let me show you what parts of the URL are variable:
invoke.objective-cloud.com/teams/$team_prefix/apps/$app_identifier/services/$name_of_service_target
As you can see Objective-Cloud is using URLs to address services. This is what happens when Objective-Cloud receives a request for a service:
- Objective-Cloud receives the request and examines the URL. The URL indicates a request for a service.
- Objective-Cloud is using $app_identifier to determine the cloud application that contains the service. Please note that Objective-Cloud is running multiple copies of your cloud application distributed between many different servers and the concrete instance of your cloud app is more or less picked randomly in order to provide scalability and reliability.
- Objective-Cloud launches the cloud application if needed and forwards the request to the cloud application.
- The cloud application receives the request and forwards the request to the service. The service is launched on demand.
- The request is transformed in a method invocation. Your code creates a value and returns it.
- This value is going back the chain and is delivered to the client which has originally executed the request.
Please note that at the point that your service has created a result it can be shut down again.
A request for the Cloud App is using a slightly different URL:
invoke.objective-cloud.com/teams/2ro0lf6gsticu/apps/com.objectivecloud.demos
In order to send a message to your cloud application you simply remove the service specific part from the URL. The JSON format for specifying the selector and arguments remains the same.
A service is considered truly stateless. Code executed in the context of an application should be considered stateless as well. You can always fake "state" by creating global variables. As mentioned earlier your cloud application may run on many different servers and Objective-Cloud does not synchronize your global variables or any other information that you might have put in global variables. This is very important to understand. Objective-Cloud does not solve this for you (yet). The main difference between a service and an application is that the application is not terminated without good reasons. A service can more or less be killed at any time. Your cloud application, once running, keeps on running as long we do see fit. We might terminate it for various reasons (system updates, installing security patches, …) but in general you can rely on them to be running longer than your service.
This enables you to do a couple of things:
- If you have a long running (+30 seconds) task we do recommend that you execute it in a cloud application instead of a service. If your cloud app method is called you can create an NSOperation, add it to a global queue and return immediately. The client will receive your response immediately and your operation can do work in the background while your client now knows that you are doing the work in the background. Your client could now either poll your cloud app (or a service) to get the result of your operation.
- Your cloud app could do things without explicit requests from clients: Crawling the web, computing answer of the universe life and everything and write the results in a shared database or upload the results of the computation to Amazon S3. We (Objective-Cloud) are actively working on making your life easier regarding storage, state and so on but we need a little bit more time).
Another difference is that by default all class method you put in CloudApp.m are "private" by default. They are not "reachable" via HTTP. This is the opposite to methods in Service.m: They are public by default.
Assuming we want to add a method to our cloud application: Open CloudApp.h and you should see something like this:
@protocol CloudAppPublishing <NSObject>
+ (NSString *)sayHelloCloudApp;
@end
#import <OCFoundation/OCFCloudApp.h>
@interface CloudApp : OCFCloudApp <CloudAppPublishing>
@end
The protocol CloudAppPublishing contains methods that the class CloudApp implements and those are the methods that will be exposed and made reachable via HTTP. Now add a new method to CloudAppPublishing like this:
@protocol CloudAppPublishing <NSObject>
+ (NSString *)sayHelloCloudApp;
+ (NSNumber *)sumOf:(NSNumber *)a and:(NSNumber *)b;
@end
#import <OCFoundation/OCFCloudApp.h>
@interface CloudApp : OCFCloudApp <CloudAppPublishing>
@end
This tells Objective-Cloud that the method +sumOf:and: is implemented by CloudApp. Now switch to CloudApp.m and implement this method like you are used to:
#import "CloudApp.h"
@implementation CloudApp
+ (NSNumber *)sumOf:(NSNumber *)a and:(NSNumber *)b {
return @(a.integerValue + b.integerValue);
}
+ (NSString *)sayHelloCloudApp {
return @"Hello Cloud App";
}
@end
Easy as pie. The code looks exactly like the one you would put in your service. As already mentioned the only difference is that Objective-Cloud guarantees that after returning the result your cloud app won't shut down without a good reason. So in theory you could do something like this:
+ (void)sumOf:(NSNumber *)a and:(NSNumber *)b {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
// Calculate a + b in the background and
NSNumber *result = @(a.integerValue + b.integerValue);
// do something useful with result: e.g: persist it somewhere
});
}