Tom King, Author at FusionReactor Observability & APM https://fusion-reactor.com/author/tom-king/ Tue, 07 Dec 2021 13:51:00 +0000 en-US hourly 1 https://wordpress.org/?v=6.6.2 https://fusion-reactor.com/wp-content/uploads/2024/03/cropped-icon-32x32.png Tom King, Author at FusionReactor Observability & APM https://fusion-reactor.com/author/tom-king/ 32 32 VueJS 101 for CFML Devs https://fusion-reactor.com/blog/technical-blogs/vuejs-101-for-cfml-devs/ Tue, 07 Dec 2021 13:51:00 +0000 https://fusionreactor.dev.onpressidium.com/?p=66719 VueJS 101 for CFML Devs I’ve been stumbling across a fair few developers recently who like the idea of using VueJS, but are not sure how to get started. VueJS can be used to build whole applications, but sometimes the … Read More

The post VueJS 101 for CFML Devs appeared first on FusionReactor Observability & APM.

]]>

VueJS 101 for CFML Devs

I’ve been stumbling across a fair few developers recently who like the idea of using VueJS, but are not sure how to get started. VueJS can be used to build whole applications, but sometimes the requirement is to just build something within an existing CFML page to make the UI more dynamic and user-friendly. This set of examples is aimed at those of you who want to dip your toes into VueJS and might have an existing CFML application that you want to enhance.

We’re mainly going to focus on the question I get the most, which is “how to do I get my data from CFML to VueJS?”.

All the code is available on Github, but we’ll go through some of the key concepts each example brings. The setup is simple, one index file, and one “remote” cfm/cfc file which we’ll call via VueJS.

VueJS 101 example 1 – Simple Message

Our aim here is simple – pressing the button should do a request to our CFML page, and return a message.

Let’s look at the index.cfm first.

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

The first thing to note is we’re just going to use regular old script tags to import Vue. We’ll also import Axios, which is a library we’ll use to make our AJAX requests.

<div id="app">
{{ message }}
<br />
<button @click="getData">Get Message</button>
</div>

Then, we’ve got a div with an id of “app”: this is our Vue instance will operate within. Our JS markup uses `{{}}` to denote the value of a variable, and our button has an `@click` handler which calls the corresponding method in the methods block.

<script> var app = new Vue({ el: '#app', data: { message: 'Hello Vue!' }, methods: { getData: function() { axios.get('remote.cfm') .then(function(response) { app.message = response.data.message; }) .catch(function(error) { console.log(error); }); } } }); </script>

Our main script block initializes the Vue instance and uses `el` to bind it to the div.

The data object is where you can define variable defaults; we’ll use a simple message variable to store the message we get back from our request.

Our methods block contains a single method, `getData()`, which is called when the button is clicked. It uses the Axios library to make a request to our CFML page and then sets the `message` variable to the response. If anything goes wrong, then the catch block will output the error to the console.

Our remote.cfm couldn’t be simpler;

header name="Content-Type" value="application/json"; data = { "message" = "Hi from CFML! The time is #now()#" }; writeOutput(serializeJSON(data));

We set the return type as JSON, create a new struct with a single field called “message”, and then return that via serializeJSON();

We can monitor the response in chrome dev tools.

Obviously, this is a very simple example: most of the time you’ll have a backend framework that will handle the incoming requests and allow you to pass back JSON easily.

VueJS 101 example 2 – Basic Array

The second example is equally simple, but this time we’ll output an array.

data: {
messages: []
},

The key difference is that in our data block, our messages js variable now defaults to an empty array.

<ul v-if="messages.length">
<li v-for="msg in messages">
{{ msg }}
</li>
</ul>

In our HTML output, the unordered list will only display when we have something via the “v-if” directive. Lastly, we’ll use a “v-for” directive to loop over the array and output the messages.

VueJS 101 example 3 – Simple Query

Next, we can try a CFML query. The Vue side is basically the same as the previous example, except we’re now renamed the array to `users`, and are outputting id, name and role within the loop.

<ul v-if="users.length">
<li v-for="user in users">
{{ user.id }} {{ user.name }} {{ user.role }}
</li>
</ul>

Our remote.cfm will now return a query result as an array.

header name="Content-Type" value="application/json";
data = queryNew(
"id,name,role",
"integer,varchar,varchar",
[
{"id"=1, name="Joe", role="admin"},
{"id"=2, name="Jane", role="user"},
{"id"=3, name="John", role="user"}
]
);
writeOutput(serializeJSON(data, "struct"));

If you return a query object via serializeJSON(), it will default to a different format, separating the columns and data; personally, I prefer the array of structs format, so in Lucee we can pass in the “struct” return type and it will do it all for us.

Example 4 – To-Do List

This last example is a bit more fleshed out – and we’ve included Bootstrap for some simple styling. It’s the ubiquitous “To-Do List” example.

Let’s look at the “backend” first; A simple CFC with some remote methods. We’re using an array in the session scope to store our to-do items.

private function setup(){
if(!structKeyExists(session, "items"))
session.items = [];
if (cgi.content_type EQ "application/json")
request.data = deserializeJSON(ToString(getHTTPRequestData().content));
}

Before each request, we check there’s an array in the session scope called “items”, and if not we’ll create it.

private function respond(){
header name="Content-Type" value="application/json";
return structKeyExists(session, "items") && isArray(session.items) ? session.items : [];
}

We’ll also set the request’s response type to be JSON.

remote function get() {
return this.respond();
}
remote function add() {
this.setup();
session.items.push({
"name": request.data.item,
"created": DateTimeFormat(now())
});
return this.respond();
}
remote function remove() {
this.setup();
ArrayDeleteAt(session.items, url.position);
return this.respond();
}
remote function clear(){
this.setup();
session.items = [];
return this.respond();
}

The `get()` function will simply return our array; `add()` will push an item to the array, and `remove()` will remove an item. `clear()` will remove all items.

There’s a bit more code in the index.cfm, so let’s go through some of the more notable changes.

The Axios configuration has changed slightly. There’s an instance of Axios which we’ve set to the `api` constant, set a timeout default of 5 seconds for any remote request, and used an interceptor to handle any errors.

const api = axios.create({
timeout: 5000
});
api.interceptors.response.use((response) => response, (error) => {
app.errors.push(error.message);
});

There’s now an error array in the Vue data object, which we’ll use to display any errors. The interceptor simply pushes any errors to this array, which are then looped over, alongside a simple dismiss button which resets the error array back to zero.

mounted: function() {
this.getItems();
},

The `mounted` function is triggered when the Vue component is initially loaded on the page – so within that, we’ll call our `getItems()` method to get the items from our remote `get` function in the CFC.

addItem: function() {
api.post('remote.cfc?method=add', {
item: this.newItem
})
.then(function(response) {
app.items = response.data;
app.newItem = null;
})
},

Inputting a new item uses one of the key concepts in Vue, that of the `v-model`, which binds a variable to the input value automatically. The `addItem()` method simply POSTs the new item to our remote `add` function. Since all the remote functions return the array back, we can just update the local array with the response.

One of the nice things about Vue is how it can easily enable and disable (or hide) elements. When Vue checks the validity of a variable, it will assume it’s invalid if it’s null, undefined of zero length. So you can see that the Add Button can be easily disabled when the input is empty.

<button class="btn btn-primary" :disabled="!newItem" @click="addItem">Add Item</button>

To remove an item, we’ll send the position of the clicked item in the javascript array (plus one, of course, remembering that JS arrays start at zero) to the remote `remove` function.

removeItem: function(position) {
api.delete('remote.cfc?method=remove&position=' + position)
.then(function(response) {
app.items = response.data;
})
}

Hopefully, this might have whetted your appetite a bit, and given you a few pointers to how you might start using VueJS in your existing CFML application.

The post VueJS 101 for CFML Devs appeared first on FusionReactor Observability & APM.

]]>
Testing and Improving Database Performance Using FRAPI https://fusion-reactor.com/blog/evangelism/testing-and-improving-database-performance-using-frapi/ Fri, 23 Jul 2021 09:02:34 +0000 https://fusionreactor.dev.onpressidium.com/?p=64712 Testing and Improving Database Performance Using FRAPI So the other day, I spotted a MySQL query (InnoDB, 5.27 if you’re interested) which was feeling non-performant. I should also point out, that SQL and testing and improving database performance are really … Read More

The post Testing and Improving Database Performance Using FRAPI appeared first on FusionReactor Observability & APM.

]]>

Testing and Improving Database Performance Using FRAPI

So the other day, I spotted a MySQL query (InnoDB, 5.27 if you’re interested) which was feeling non-performant. I should also point out, that SQL and testing and improving database performance are really not my forte. So please try not to judge me too harshly.

It’s actually a really simple query, so easy to demonstrate here:

UPDATE tokens SET deletedat = '2021-06-29 10:58:06.105' WHERE ( tokens.expiresat < '2021-06-29 10:58:06.0' ) AND ( tokens.deletedat IS NULL )

Tokens Table

So in my tokens table, this query would soft delete (via the deletedat column) any row where the expiry had passed. This has been running just fine for a year or so. But recently has started taking a bit longer. This query was being triggered on most/all API requests. With the table now over 100,000 rows, it was taking between 70ms – 350ms on average. This for a simple UPDATE felt bad and in need of a bit of love.

The table has an id column as the primary key, but was a unique UUID, non-incrementing, for each row.
The obvious solution was an index, but it took me a little while to get the index correct. Indexing just expiresat still resulted in all 100k rows being examined as I’d ignored that deletedat was in the WHERE clause. After a few local tests, I managed to get an index that had deletedat and expiresat in it, examining a mere handful of rows, and executing in 2-8ms. So I was pretty confident in pushing this change to production.

Ben Nadel’s Book

Before I did, however, I decided to take a page out of Ben Nadel’s book. I would use the FusionReactor API to wrap my changes in a custom transaction. I won’t go into massive detail here, as Ben did a great job explaining it here alongside other posts in his blog. Basically, I ended up using his JavaAgentHelper.cfc and then simply wrapped the code I wanted to track:

FRstartedAt = getTickCount();
javaAgentHelper.segmentWrap("ExpireTokens", () => {
  // My Model call which triggers the query
  expiredTokens=model("token").deleteAll(instantiate=false, where="expiresAt < '#now()#'"); 
});
javaAgentHelper.metricAdd( "/custom/ExpireTokens", ( getTickCount() - FRstartedAt ) );

Advantages

This approach has a couple of really useful advantages.

Firstly, you can visually see the segment in the trace within FusionReactor (all database queries are logged anyway but this just makes it very clear which part you’re concerned with). So when scanning requests, you get something more helpful than just “JDBC Request”.

Testing and Improving Database Performance advantage screenshot 1

Secondly, as you’ve taken the time to wrap the code you’re interested in into a custom transaction, you can then build a custom graph via the metricAdd to track it over time. For me, this was really helpful to see if the performance gain was real in a production environment, and not just a fluke of local development. So I deployed the wrapped code first (even though the query was still under-performing) just so I could “before and after” the results.

Testing and Improving Database Performance advantage screenshot 2

It should be fairly obvious from the above the pre/post-deployment moment – and that’s where FusionReactor really helps. It gives you more confidence in the effectiveness of fixes going into production.

Now I’ve got this method ready to use in the code base, it’s pretty trivial to apply it to other problem areas. Not just when testing and improving database performance or queries!

The post Testing and Improving Database Performance Using FRAPI appeared first on FusionReactor Observability & APM.

]]>
Revisiting CFML Operators In Lucee https://fusion-reactor.com/blog/evangelism/revisiting-cfml-operators-in-lucee/ Thu, 22 Jul 2021 11:48:33 +0000 https://fusionreactor.dev.onpressidium.com/?p=64681 Revisiting CFML Operators In Lucee Operators are ubiquitous. As developers, we use them every day, and maybe even in every line of code. Why is it then, I never seem to find the time to revisit these language essentials? Perhaps … Read More

The post Revisiting CFML Operators In Lucee appeared first on FusionReactor Observability & APM.

]]>

Revisiting CFML Operators In Lucee

Operators are ubiquitous. As developers, we use them every day, and maybe even in every line of code.

Why is it then, I never seem to find the time to revisit these language essentials? Perhaps it’s because I’m guilty of “going with what I know works”; maybe it’s the act of re-training my thought processes which is difficult; either way, it can certainly do no harm to have a refresh occasionally.

It can sometimes take a new language, product, or version of something to trigger that refresh. Recently I’ve been doing a lot of VueJS, and switching between JS and CFML was enough to trigger a need to remind myself of the fundamentals. This blog, therefore, looks into revisiting CFML Operators in Lucee.

Strict Comparison Operator

Take this comparison operator === for instance. In Vue, my linting setup would always moan at me if I used == in place of ===, and rightly so; In JS, == returns true if the operands are equal; but === only returns true if the operands are equal AND of the same type.

Naturally, I’d start back on my CFML based API, and end up using === in the same conditions (as let’s face it, cfscript and javascript syntax these days are awfully close), but the Lucee version of this operator works differently; it returns true if the operands are the same object in memory. Cue lots of head-scratching from me.

Ternary Operator

Although the main reason for revisiting CMFL Operators in Lucee is to remind me of the fundamentals, there is another reason to go back and look at the basics and that is actually laziness. Are there any new tricks so I can physically write less code? Or better yet, more concise, performant, and hopefully more readable code?

Whilst I’ve been using it for a while now, the ternary operator has definitely worked its way into my go-to toolbox. My new favourite thing is replacing if/else statements with a single ternary operator.

Take for example this bog-standard statement:

if( someCondition ){
    foo = 1;
} else {
    foo = 2;
};

With a ternary operator, we can drop this down to a single declaration:

foo = someCondition ? 1 : 2;

which I find pretty neat and clear. It also helps prevent a lot of nested if/else statements, especially when assigning values to variables based on a condition.

We can replace:

if( someCondition ){
    foo = 1;
    if ( somethingElse ){
        bar = 3;
    } else {
        bar = 4;
    }
} else {
    foo = 2;
};

with

foo = someCondition ? 1 : 2;
bar = someCondition && somethingElse ? 3 : 4;

which I find a lot cleaner and clearer.

Null Coalescing Operator

Otherwise known as the “Elvis operator”. How does this compare to a ternary operator?

// Example 1 - Ternary
foo = someValue ? 1 : 2;

// Example 2 - Elvis
foo = someValue ?: 2;

They look pretty close but will do quite different things.

If someValue exists, then a ternary operator will pick 1 or 2 dependent on the outcome of the condition, as we’ve seen above.

If someValue doesn’t exist, i.e, is Null undeclared, then that line would rightly throw an error.

The Elvis operator, on the other hand, will look at the left-hand condition, and if it exists, will use it. If it doesn’t, will then use the right-hand value.

So that means we can take much more verbose code like:

if( isDefined("someValue") ){
    foo = 1;
} else {
    foo = 2;
}

and replace with:

foo = someValue ?: 2;

This can actually be really helpful in navigating unknown structs, where you’re looking for something deep and nested – i.e, transversing a JSON result from an API;

req = {
    foo = 1
};
result = req?:foo?:bar?:baz;
writeDump(result);

This will safely return req.foo – but if it had further children, would continue until it hit an undefined variable.

Hopefully, this blog has helped to refresh your knowledge on CFML Operators in Lucee and these couple of examples might encourage you to revisit operators soon!

The post Revisiting CFML Operators In Lucee appeared first on FusionReactor Observability & APM.

]]>
Watermarking PDFs In Lucee 5.3.7 Without Using CFPDF https://fusion-reactor.com/blog/evangelism/watermarking-pdfs-in-lucee-5-3-7-without-using-cfpdf/ Tue, 26 Jan 2021 10:21:42 +0000 http://fusionreactor.dev.onpressidium.com/?p=62212 Watermarking PDFs In Lucee 5.3.7 Without using CFPDF Recently, I’ve needed to add a watermark to PDFs but struggled with Lucee’s current implementation in 5.3.x..  Watermarking PDFs In Lucee 5.3.7 without using CFPDF is usually pretty straightforward, via <code> <cfpdf action="addwatermark" … Read More

The post Watermarking PDFs In Lucee 5.3.7 Without Using CFPDF appeared first on FusionReactor Observability & APM.

]]>
Watermarking PDFs In Lucee 5.3.7 Without using CFPDF

Recently, I’ve needed to add a watermark to PDFs but struggled with Lucee’s current implementation in 5.3.x..  Watermarking PDFs In Lucee 5.3.7 without using CFPDF is usually pretty straightforward, via

<code>
<cfpdf action="addwatermark" source="#source#" image="#image#" destination="#destination#" overwrite="yes">
</code>

However, there appear to be a fair few issues with cfpdf() at the time of writing:

Thankfully, there is a workaround by directly calling the iText Java libs which are already in Lucee 5.x. You can use the function below as a bit of a hacky fix in the meantime! Note, this is only tested in Lucee 5.3.7 so your mileage may vary.

<cfscript>

  /**

* Add a image as a watermark to a PDF using iText in Lucee 5.3

*

* @source string, i.e Full path to Input File: expandPath("myFile.pdf")

* @destination string i.e Full path to Output File: expandPath("myFile_Watermarked.pdf")

* @image string i.e Full path to Watermark Image: expandPath("watermark.png")

* @x Watermark image x offset, defaults to 0

* @y Watermark image y offset, defaults to 0

* @foreground Whether to add watermark on top or behind content

*/

function watermarkPDF(

required string source,

required string destination,

required string image,

numeric x = 0,

numeric y = 0,

boolean foreground = true

){

// Create PDF reader

local.pdfReader = createObject("java", "com.lowagie.text.pdf.PdfReader").init(arguments.source);

// Fill form fields

local.outputStream = createObject("java", "java.io.FileOutputStream").init(arguments.destination);

local.pdfStamper = createObject("java", "com.lowagie.text.pdf.PdfStamper").init(local.pdfReader, local.outputStream);

// Create image object for watermark image

local.imageObj = createobject("java", "com.lowagie.text.Image");

//  Read watermark image

local.img = local.imageObj.getInstance(arguments.image);

// Add watermark image to every page

local.i = 0;

// Loop PDF pages

while (local.i LT local.pdfReader.getNumberOfPages()) {

local.i = local.i + 1;

local.pdfContentByte = arguments.foreground?

local.pdfStamper.getOverContent( javacast("int", local.i) )

: local.pdfStamper.getUnderContent( javacast("int", local.i) );

// Set position of image

local.img.setAbsolutePosition(javacast("float", arguments.x),javacast("float", arguments.y));

// Add watermark image to looped page

local.pdfContentByte.addImage(local.img);

}

// flattern form

local.pdfStamper.setFormFlattening(true);

// Close and create destination pdf file

local.pdfStamper.close();

local.outputStream.close();

}

</cfscript>

```

Example Usage:

```
<cfscript>
watermarkPDF(
    expandPath("/files/A1_MyDocument.pdf"),
    expandPath("/files/A1_MyDocument_Watermarked.pdf"),
    expandPath("/files/watermark.png")
);
</cfscript>
```

Bear in mind, watermarking PDFs won’t stop a user from easily removing the watermark in Acrobat Pro unless you add an owner password to restrict editing (and, arguably, even then there are ‘unethical’ ways around that).

Thankfully that functionality currently works in Lucee 5.3.7, so we use cfpdf to restrict access:

```
<cfpdf action="protect"
    encrypt="AES_128"
    source="#FullPathToOutputFile#"
    newOwnerPassword="myAwesomePassword"
    permissions="none">
```

 

The post Watermarking PDFs In Lucee 5.3.7 Without Using CFPDF appeared first on FusionReactor Observability & APM.

]]>
Basic Load Testing With Locust https://fusion-reactor.com/blog/evangelism/basic-load-testing-with-locust/ Mon, 07 Dec 2020 18:53:23 +0000 http://fusionreactor.dev.onpressidium.com/?p=59097 Basic load testing with Locust No-one likes to get caught out with scaling issues. Your app or site goes viral, or you simply get a tonne of unexpected traffic through a favourable blog post, and without some preparation, all hell … Read More

The post Basic Load Testing With Locust appeared first on FusionReactor Observability & APM.

]]>

Basic load testing with Locust

No-one likes to get caught out with scaling issues. Your app or site goes viral, or you simply get a tonne of unexpected traffic through a favourable blog post, and without some preparation, all hell can break loose, your app fails and users are left disappointed (not least the business owners).

One of the most common ways in preparing for unexpected traffic is by using load testing. Load tests can range from blindingly simple (hit endpoint ‘x’ a number of times) to complex constructions which model user behaviour, including logins, logouts, mock purchases and the like.

Having a baseline test which you can replicate consistently – perhaps after an environment change – can help give you insight as to what capacity your setup has.

Load Testing Tools

There are a fair few load testing tools – some are web based (SaaS) offerings, where you employ a premade engine which will fire mock traffic at your app from a bank of ready to go machines – usually cloud instances; naturally, the more traffic/fake users you want to throw at your site, the more you pay. For lower level tests, the other common option is to run a script or app on your local machine to load up and fire those requests – you’ll be bound by your local CPU/RAM and network capacity, and all the traffic will come from your IP: whilst most of the time this can be fine for a low level test, when you’re trying to “outgun” a cluster with scalable resources, you’re probably going to run out of steam. Some tools support running load tests distributed over multiple machines, and can therefore be used to simulate millions of simultaneous users too.

A simple load test with Locust.io

One easy to use and open source tool is Locust (https://locust.io) – it’s python based, but the syntax is simple and easy to get your head around. It can be installed locally via `pip` – `pip install locust`, which (assuming you’ve got `pip` already) is very straightforward. Once installed you can run `locust -V` to verify your version.

Locust runs a local webserver where you can monitor your progress. To get started, all you need to do is create a local `locustfile.py` in your root directory, and run `$ locust`.

A typical locust file

```
from locust import HttpLocust, TaskSet

def index(l):
l.client.get("/", verify=False)

def task1(l):
l.client.get("/v1/environment", verify=False)

class UserBehavior(TaskSet):
tasks = {index:1, task1: 7}

class WebsiteUser(HttpLocust):
task_set = UserBehavior
min_wait = 5000
max_wait = 9000
```

This is about as simple as it gets – it will hit the site root, and then an endpoint of `/v1/environment` seven times – obviously this could be anything, and about page, or whatever.

Running The Test

Start the web interface with `$ locust –host=https://yourdomain.com` (replacing yourdomain.com as appropriate) and then open `http://localhost:8089/` – Note 127.0.0.1 isn’t bound so use localhost. You’ll be able to set the number of users to simulate, and start the “swarm”. Start with about 300 / 50.

When you’re done ctrl + C in the terminal to stop the locust process, which should give you a summary output

The Results

The graph should be fairly self explanatory; over the course of about an hour, the number of requests per minute goes up to c.285, simulating about 2,000 users, and things start to get a bit wobbly in the last 5 minutes or so.

Looking In FusionReactor

The endpoints I’m using in this test are deliberately simple – there’s no user sessions (it’s a stateless API) and only one DB call per request. This is a low powered fargate cluster running Commandbox and a CFWheels app. These containers only have 2GB Ram and 1 CPU unit.

Looking at the result in FusionReactor (cloud) we can see the two app instances/tasks – selecting one shows us (literally) half the traffic as it’s behind a A-B load balancer. The memory usage remains in check, and the CPU rises expectedly until it peaks at 100%, after which the response time goes through the roof.

Conclusion

What’s nice about this approach is we can get an idea of simple baseline behaviour when under simple load. It’s not trying to be a “complex” user, who might be doing POST requests, invoking CFHTTP calls, generating PDFs or anything taxing – it’s merely a reference point to understand the raw throughput of the setup.

A proper load test would emulate a typical users interactions for the site – some users would drop off after one hit, some would stick around, some would login etc. Building a more comprehensive test will always be application specific.

The post Basic Load Testing With Locust appeared first on FusionReactor Observability & APM.

]]>
ColdFusion and Microservices https://fusion-reactor.com/blog/technical-blogs/coldfusion-and-microservices/ Tue, 01 Dec 2020 10:45:03 +0000 http://fusionreactor.dev.onpressidium.com/?p=57452 The all-new Adobe ColdFusion 2021 has just been released with dozens of features introduced to boost efficiency, security, scalability, language improvement, in addition to much newer instruments for performance monitoring and profiling. A substantial focus of CF2021 is support of … Read More

The post ColdFusion and Microservices appeared first on FusionReactor Observability & APM.

]]>

The all-new Adobe ColdFusion 2021 has just been released with dozens of features introduced to boost efficiency, security, scalability, language improvement, in addition to much newer instruments for performance monitoring and profiling. A substantial focus of CF2021 is support of microservices architecture.

As a variant of the service-oriented framework style, Microservices is a pattern that organizes complex applications into a collection of smaller-scale but related services deliveries, which CF2021 supports in a number of ways.

ColdFusion Microservices Title Image

1. Lightweight Installer Package

CF2021 comes equipped with either a GUI installer or a featherweight express installer package (currently between the range of 100 – 200 MB as against the GUI installer size of about 1GB) designed to allow for the automation of repeatable installations with the exact features you require. The lightweight installer package gets CF up and running in a matter of seconds.

2. Scriptable configuration

CF2021 offers a new scriptable configuration tool, cfsetup, which supports creating json configuration files that can be imported at CF startup. The tool supports displaying configuration settings and more, and it expands greatly on the former (but still-supported) ColdFusion ARchive/CAR feature. It’s now very easy to completely automate the implementation of CF, whether in the cloud or on-premise.

3. Cloud Services integration

CF2021 continues the microservices theme with several substantial new features supporting cloud services (in both AWS and Azure), from storage (AWS S3 and Azure Blob), message queuing (AWS SQS and Azure Message Bus), nosql cloud databases (AWS dynamoDB and Azure Cosmos DB), as well as notification (AWS SNS) and email (AWS SES) services. Again, whether deploying ColdFusion in the cloud or on-premise, CF2021 adds significant new integration possibilities.

4. Serverless deployment via AWS Lambda

Another key aspect of microservices architecture is the option of serverless deployment (also known as “functions as a service”), as implemented in services such as Azure Functions and AWS Lambda. CF2021 continues its microservices support with a feature to deploy CFML to AWS Lambda, so that you have no server to manage and resources are used only on-demand.

5. Provision Docker Images

CF2021 offers Docker images (as were provided also for CF2018 and 2016) which are available via bintray.com and as discussed here. The new versions continues the microservices theme, from being smaller and faster to start as well as supporting two new environment variables related to features above:

  • ImportCFSettings: imports the cfsetup-based JSON configuration file, to automate Admin settings
  • InstallModule: imports a comma-separated list of CF2021 modules to be installed

CF2021 allows you to deploy and scale CFML applications in any environment seamlessly, including via continuous integration and continuous delivery (CI/CD).

Microservices Diagram

And of course all these CF2021 new features expand upon the various aspects of CF that have long made it capable to develop applications quickly and integrate with external services, whether in the cloud or on-premise. CF2021 also supports configuration of cloud/RDS databases as CF datasources. And through the ColdFusion Enterprise API manager, teams can easily create, manage, and monitor their API services.

6. Other improvements in CF2021

Other notable features added to the CF2021 release include SAML (single sign-in) integration, support for the MongoDB noSQL database, and many language improvements including rest and spread operators, parallelism on arrays and structs, iterator and static block support for CFCs, IIFE (Immediately Invoked Function Expression), and more. CF2021 also provides for direct coding of Java within CFML, as well as still other new features.

Conclusion

With its many new features and focus on modern development, the CF2021 release may be the most professional version to be introduced since the debut of the ColdFusion development platform 25 years ago.

The post ColdFusion and Microservices appeared first on FusionReactor Observability & APM.

]]>
Adobe ColdFusion 2018 Versus Lucee https://fusion-reactor.com/blog/technical-blogs/adobe-coldfusion-2018-versus-lucee/ Tue, 17 Nov 2020 11:43:22 +0000 http://fusionreactor.dev.onpressidium.com/?p=55988 Adobe ColdFusion and Lucee are two leading web application development tools based on CFML (ColdFusion Markup Language) code. Adobe ColdFusion was initially developed to connect HTML and the database easily. With the release of Adobe ColdFusion 2018, a full-blown scripting language … Read More

The post Adobe ColdFusion 2018 Versus Lucee appeared first on FusionReactor Observability & APM.

]]>

Adobe ColdFusion and Lucee are two leading web application development tools based on CFML (ColdFusion Markup Language) code. Adobe ColdFusion was initially developed to connect HTML and the database easily. With the release of Adobe ColdFusion 2018, a full-blown scripting language with CFML is incorporated along with an IDE. Further, the platform has been updated and enhanced to build more modularized, maintainable, and responsive web applications.

The popularity of CF led to the development of many open-sourced platforms, among which Lucee became a strong competitor for Adobe ColdFusion. Lucee stands up as an alternative CFML engine that employs dynamically typed scripting language for the Java Virtual Machine for the rapid development of web applications. 

This article shall give you a briefing on both software by comparing and contrasting each other based on the below concerns.

Surface Comparison

Price

Adobe ColdFusion 2018 comes with a price tag. Depending on the package chosen, the price varies. CF Standard costs from $2,499, while the CF Enterprise with some enhanced features comes at $9,499 onwards.

Meanwhile, Lucee is free and open-sourced. This stands as a major plus point in choosing between the two, encouraging novice developers to shift towards Lucee instead of Adobe.

Installation and Requirements

Installing Adobe ColdFusion 2018 requires a lot of prior work, such as ensuring the server connection. This is based on the platform you work with. 

In contrast, Lucee streamlines the installation process by automatically carrying out server connections. This makes Lucee a stand-alone app and is compatible with Windows and Linux.

User Support

A devoted support team stands by Adobe that can be reached through phone or via online tickets for direct support. They also help with troubleshooting and have readily available testing tools. 

Lucee is more of a community-based software. The members of the Lucee Association Switzerland help with the issues arising for its users. However, for larger-scale issues and troubleshooting, third party commercial support services are to be sought.

Language Support 

Adobe CF works on CFML. However, it still supports other programming languages such as .NET, ActionScript, and CFScript. Moreover, ColdFusion is a Java EE platform that can be combined with the rest of Java classes and libraries holding some exclusive proprietary functionalities.

Lucee also allows you to work with java classes. But it is also proved to be better than Adobe CF  when working with JSON. 

Hosting

ColdFusion features a single and central CFADMIN that is accessible only by the HR host. The admin settings are also all global and cannot be customized as per the website.  

When compared, Lucee holds a higher advantage with shared hosting, allowing each website to have its web admin. The CFML settings, mail configurations, and data sources can be tailored depending on the application you work with.

Security Concerns

Adobe works best on identifying and removing any securing issues when raised. They break down potential threats and security risks into two categories. Priority scale and Severity scale and work on debugging accordingly. With the release of the latest CF version in 2018, some major security issues like deserialization of untrusted data were solved. 

Resolving security threats is a bit of a challenging task for Lucee. Communicating the security issues to its association members takes more time than resolving them. Hence, this process could take a while leading to more complicated issues in-between.

Special features

Compared to Lucee, Adobe ColdFusion carries some special features for the price you pay.

Applications In The Cloud

  • With AWS S3 and Azure Blob, data can be accessed faster. Multi-cloud services accessible with the same syntax and a single line of code to get to different databases.

 

  • AWS DynamoDB and MongoDB are used in Adobe CF to work with large data volumes with a built-in interface for NoSQL databases. Unstructured and structured data can be stored and easily converted into schemas and fields. 

 

  • Simple messaging services through Azure Service Bus and AWS SNS/SQS. Messaging queue services can be accessed easily, transmitting any data volume.

 

  • Relational database services in the cloud at a lower cost via Amazon RDS and Azure database.

 

  • Any type of application or service can be run through ColdFusion codes with AWS Lambda holding no administration and with automatic scaling.

Accelerate DevOps Pipeline

  • All the REST services can be created and managed via the REST Playground.

  

  • CLI and Read-Eval-Print Loop (REPL) Support.

 

  • Create and administer database-independent apps using Object-relational mapping support without writing any SQL.

 

  • Emails can be managed effectively using an SMTP server.

 

  • PDF manipulation with full access to Document Description XML (DDX).

 

  • Mobile apps can be developed via CFML employing Adobe’s built-in integration and Adobe PhoneGap.

Conclusion

Thus, it can be concluded that both Adobe CF and Lucee work well with CFML making them worthwhile. Yet, Lucee can be much cheaper with improved speed and shared hosting. However, with Adobe often upgrading their service with regards to certain aspects like security and some features special on its own when creating enterprise standard applications, it stands better at the price you pay. 

The post Adobe ColdFusion 2018 Versus Lucee appeared first on FusionReactor Observability & APM.

]]>
Performance Issue With Redis Session Management On Adobe ColdFusion Servers With FusionReactor Or Adobe Performance Monitoring Toolset (PMT) https://fusion-reactor.com/blog/evangelism/performance-issue-with-redis-session-management-on-adobe-coldfusion-servers-with-fusionreactor-or-adobe-performance-monitoring-toolset-pmy/ Thu, 05 Nov 2020 11:43:28 +0000 http://fusionreactor.dev.onpressidium.com/?p=55394 Introduction We recently had a performance issue with Redis session management in FusionReactor where a user saw a high CPU when running FusionReactor reported to our technical support team. Upon investigating the issue, we found this was due to both … Read More

The post Performance Issue With Redis Session Management On Adobe ColdFusion Servers With FusionReactor Or Adobe Performance Monitoring Toolset (PMT) appeared first on FusionReactor Observability & APM.

]]>

Introduction

We recently had a performance issue with Redis session management in FusionReactor where a user saw a high CPU when running FusionReactor reported to our technical support team. Upon investigating the issue, we found this was due to both FusionReactor and the Adobe PMT tracking sessions by making a large number of calls to the Redis database.

In FusionReactor 8.2.3 we released a fix that will stop session tracking if Redis sessions are in use. The result of this is that you will only see an overview of total session activity, there are no metrics for the active, created, or destroyed sessions from ColdFusion.

In the Sessions page of FusionReactor you would only see something like:

Abode have an open bug for this (https://tracker.adobe.com/#/view/CF-4205489), this fix has been scheduled for an HF7 release. Until Adobe fixes the issue, we do not enable full session tracking when using Redis sessions in ColdFusion 2018.

To Confirm If You Are Affected By This Issue

Go to Transactions > Activity and filter by Redis transactions. You will see something similar to:

FusionReactor APM

This performance issue with Redis session management is caused by two factors:

  • A bug in FusionReactor that every second sends 2 get requests to Redis for each active session
  • A bug in the Adobe PMT that every second sends 1 get request to Redis for each active session

These Redis calls are all tracked by FusionReactor which slows down the performance of the server due to the volume of requests when a ColdFusion server has a high number of sessions even if these sessions were created on a different ColdFusion server but are using the same Redis server for the sessions.

The Workaround

To work around this issue please upgrade to version 8.2.1 or higher of FusionReactor which disabled session tracking from FusionReactor. Note that in this version, there will still be one set of Redis calls made to Redis if you are viewing the session information in the Adobe PMT.

When the bug for session tracking is fixed in ColdFusion 2018, we will update FusionReactor to reenable session tracking.

Issue Details

The post Performance Issue With Redis Session Management On Adobe ColdFusion Servers With FusionReactor Or Adobe Performance Monitoring Toolset (PMT) appeared first on FusionReactor Observability & APM.

]]>
How To Retain FusionReactor Logs In Docker Environment https://fusion-reactor.com/blog/evangelism/how-to-retain-fusionreactor-logs-in-docker-environment/ Mon, 02 Nov 2020 10:45:54 +0000 http://fusionreactor.dev.onpressidium.com/?p=55079 When running in a docker based environment it can be difficult to retain the logs for your application and for the monitoring tools that you use. To overcome this there are several options that you can use: An external platform … Read More

The post How To Retain FusionReactor Logs In Docker Environment appeared first on FusionReactor Observability & APM.

]]>

When running in a docker based environment it can be difficult to retain the logs for your application and for the monitoring tools that you use. To overcome this there are several options that you can use:

  • An external platform to consume the log files.
  • A docker volume to retain the files after the docker container has terminated.

There are pros and cons to each method, in our cloud solution we utilize both. Firstly we ship a lot of out logs to an external service to archive and indexing for search and alerts. We additionally produce a dynamically generated docker volume to store the logs for the application and for FusionReactor logs itself (that’s right we use FusionReactor to monitor FusionReactor!).

Background

So firstly what is a docker volume? Well to really know the ins and outs of the docker volumes I suggest that you read the official documentation from the docker guys. (https://docs.docker.com/engine/admin/volumes/volumes/).

But in case you do not want to read all of that, a docker volume is effectively a shared file system location that is not deleted when the container is destroyed. This allows you to persist the data in this volume after the docker has terminated, so you can go back and have a loot at crash dumps, log file etc.

Configuration

To configure a docker container to use a volume you only need to add the volume paths for the internal and external folder locations. On the command line that would look like this:

-v /path/on/host:/path/in/container

If you are using docker-compose you can add this to the file like this:

volumes:
  - /path/on/host:/path/in/container

Runtime

So if you run your container with a shared volume, how do you get the FusionReactor logs to appear in this location?

For this, there are two options. Either you can create the volumes on the location your FusionReactor logs go (and archive if using the default logger), or you can change the log directory of the FusionReactor logs instance using a small bash script.

So the first approach is to use two docker volumes, as shown here:

volumes:
  - /opt/docker/share/fusionreactor/tomcat/log:/opt/fusionreactor/instance/tomcat/log
  - /opt/docker/share/fusionreactor/tomcat/archive:/opt/fusionreactor/instance/tomcat/archive

This will put the logs from the FusionReactor inside the docker container, in the directory /opt/docker/share/fusionreactor/tomcat on the host machine. Unfortunately, this can have some side effects if you configure this for more than one FusionReactor, as all the FusionReactor instances will try to log to the same files. This can cause errors from the loggers, and more importantly, make it hard to understand the logs (as they will contain 2 instances logs).

To overcome this problem you can use a small script when the docker starts to modify the FusionReactor configuration to allow for multi-tenant logging.

Dynamic Runtime

The first step is to create a docker volume where we can place all these log files, for our system we use /opt/docker/share. So in the docker-compose file you can add:

volumes:
  - /opt/docker/share:/opt/docker/share

As you can see we use the same path inside the docker as on the host, now we need to create a new folder inside this path (as part of the docker run script to allow for multiple FusionReactors to log here at the same time. How we do this is to run this small snippet in the EntryPoint of the docker container.

FR_LOG_SHARE_PATH="/opt/docker/share/${HOSTNAME}"
mkdir --parents ${FR_LOG_SHARE_PATH}/log
mkdir --parents ${FR_LOG_SHARE_PATH}/archive
echo "logdir="${FR_LOG_SHARE_PATH}/log >> /opt/fusionreactor/instance/tomcat/conf/reactor.conf
echo "fac.archive.root="${FR_LOG_SHARE_PATH}/archive >> /opt/fusionreactor/instance/tomcat/conf/reactor.conf

... continue with starting your application ...

With this your FusionReactor will now log and archive to this docker volume, allowing you to access these files after the container has been terminated.

Conclusion

By using this approach you can now retain the log files for your FusionReactor instance after the container has been terminated. This approach also allows you to add additional files to these shares. For example, we also add the Java options to produce a heap dump and hs_error file to a similar docker volume in the event of a JVM Out Of Memory error or other fatal errors.

Unfortunately, this approach does have a side effect of ‘leaking’ disk space as the host directory /opt/docker/share will not be cleaned up by the docker daemon. This can easily be overcome with a small cron job or other processes to periodically delete older files.

Issue Details

The post How To Retain FusionReactor Logs In Docker Environment appeared first on FusionReactor Observability & APM.

]]>
How To Secure FusionReactor And JSP Applications In Tomcat Using LDAP https://fusion-reactor.com/blog/evangelism/how-to-secure-fusionreactor-and-jsp-applications-in-tomcat-using-ldap/ Fri, 30 Oct 2020 10:07:12 +0000 http://fusionreactor.dev.onpressidium.com/?p=54776 Overview FusionReactor provides different types of user accounts (Administrators/Manager/Observer), however, if you would like to restrict access to FusionReactor for individual users, you can do this via LDAP authentication. This blog post will guide you through configuring tomcat to use … Read More

The post How To Secure FusionReactor And JSP Applications In Tomcat Using LDAP appeared first on FusionReactor Observability & APM.

]]>

Overview

FusionReactor provides different types of user accounts (Administrators/Manager/Observer), however, if you would like to restrict access to FusionReactor for individual users, you can do this via LDAP authentication. This blog post will guide you through configuring tomcat to use LDAP authentication to restrict access to both FusionReactor and JSP Applications.

We will split this guide into 5 distinct sections:

  1. Configuring LDAP
  2. Configuring the server.xml file
  3. Configuring the JSP application
  4. Configuring the FusionReactor web root
  5. Disabling the external web root of FusionReactor

1.  Configuring LDAP

When configuring LDAP for use with tomcat you are required to create a collection of individuals and a collection of groups (one group per required tomcat security role), each user can be assigned to one specific group.

In this example, FusionReactor and JSP applications are assigned to separate tomcat roles. The domain structure is as follows:

dn: dc=mydomain,dc=com
objectClass: dcObject
dc:mydomain

dn: ou=people,dc=mydomain,dc=com
objectClass: organizationalUnit
ou: people

dn: ou=groups,dc=mydomain,dc=com
objectClass: organizationalUnit
ou: groups

dn: uid=jsmith,ou=People,dc=mydomain,dc=com
objectClass: inetOrgPerson
uid: jsmith
cn: John Smith
sn: Smith
userPassword: myPassword

dn: uid=ajones,ou=People,dc=mydomain,dc=com
objectClass: inetOrgPerson
uid: ajones
cn: Adam Jones
sn: Jones
userPassword: myPassword

dn: cn=fusionreactor,ou=groups,dc=mydomain,dc=com
objectClass: groupOfUniqueNames
cn: fusionreactor 
uniqueMember: uid=jsmith,ou=People,dc=mydomain,dc=com

dn: cn=myApplication,ou=groups,dc=mydomain,dc=com
objectClass: groupOfUniqueNames
cn: myApplication
uniqueMember: uid=ajones,ou=People,dc=mydomain,dc=com

You could instead create one group for example “admin” and use this for FusionReactor and the JSP application.

2. Configuring The Server.Xml File

Tomcat in its default installation will use a local database to authenticate user access. We need to modify the server.xml file typically located at {Tomcat Root Directory}/conf/server.xml so that tomcat will instead use the LDAP server as it’s authentication service.

To do this, first open the server.xml file in a text editor, you should replace the default Realm element tag:

<Realm className="org.apache.catalina.realm.LockOutRealm">
   <!-- This Realm uses the UserDatabase configured in the global JNDI
        resources under the key "UserDatabase".  Any edits
        that are performed against this UserDatabase are immediately
        available for use by the Realm.  -->
   <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
        resourceName="UserDatabase"/>
</Realm>

With the following:

<Realm   className="org.apache.catalina.realm.JNDIRealm"
  connectionURL="ldap://myDomain.com:389"
  userPattern="uid={0},ou=people,dc=myDomain,dc=com"
  roleBase="ou=groups,dc=myDomain,dc=com"
  roleName="cn"
  roleSearch="(uniqueMember={0})"
/>

More information on realms can be found here: https://tomcat.apache.org/tomcat-7.0-doc/realm-howto.html

3.  Configuring The JSP Application

By default any application you place in the webapps directory of tomcat will be accessible without authentication, however, you may have an application that should only be accessible to a specific user, you can achieve this by modifying the web.xml file of the application this can usually be found at {Tomcat Root Directory}/webapps/{App Name}/WEB-INF/web.xml

Within the “web-app” element tag add the following:

<security-constraint>
   <web-resource-collection>
      <web-resource-name>FusionReactor</web-resource-name>
      <url-pattern>/*</url-pattern>
   </web-resource-collection>
   <auth-constraint>
      <role-name>myApplication</role-name>
   </auth-constraint>
</security-constraint>
<login-config>
   <auth-method>BASIC</auth-method>
   <realm-name>SecuredApp</realm-name>
</login-config>

After that, it will block any user with an unauthorized role from accessing your application. It is possible to define multiple authorized roles my duplicating the “role-name” element tag for example:

<auth-constraint> 
     <role-name>myApplication</role-name> 
     <role-name>fusionreactor</role-name> 
</auth-constraint>

4. Configuring The FusionReactor Web Root

With the default configuration of FusionReactor, you will be able to access the Application Performance Monitor through either the application server port (external port), 8080 for tomcat, or the instance port defined in the java arguments (internal port). Accessing FusionReactor through the external port uses the web root, the path to FusionReactor on the port.

By default, this is “/fusionreactor/” so if the internal port is enabled you will be able to access your FusionReactor instance at http://localhost:8080/fusionreactor/.

You can change this value by navigation to FusionReactor > Settings > Web Root:

 

To configure LDAP security you will first need to create the following web app directory structure:

 

Ensuring you replace “fusionreactor” with your web root.

Your web.xml file should contain the following:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                             http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">        <security-constraint>
        <web-resource-collection>
          <web-resource-name>FusionReactor</web-resource-name>
          <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
           <role-name>fusionreactor</role-name>
        </auth-constraint>
      </security-constraint>
       <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>SecuredApp</realm-name>
      </login-config>
</web-app>

This will ensure that any user that does not have the tomcat role fusionreactor cannot access the instance.

At this stage, you will be able to test that both your application and FusionReactor authentication access is working as expected.

5. Disabling The External Web Root Of FusionReactor

Although your external port is now secured, FusionReactor is still accessible over the internal port without LDAP authentication. To stop this we simply need to disable the external port.

You can do this in 2 ways:

  1. In the settings page – Simply disable the port

 

2. In the java arguments

    • Windows – Run the tomcatw.exe application within {Tomcat Directory}\bin
    • Linux – Open the setenv.sh file in a text editor this file should be located at {Tomcat Directory}/bin/setenv.sh

In the -javaagent argument remove the address={port number} configuration option, for example:

-javaagent:/opt/fusionreactor/instance/tomcat7/fusionreactor.jar=name=tomcat7,address=8098 will become –javaagent:/opt/fusionreactor/instance/tomcat7/fusionreactor.jar=name=tomcat7

Conclusion

After following the above steps we should now be in the following state:

  • An unauthorized user cannot access either the JSP application or FusionReactor
  • To Authenticate a user your LDAP server will be contacted
  • Only users with appropriate tomcat roles will be able to access the JSP application of FusionReactor
  • FusionReactor will not be accessible on the internal port

Issue Details

The post How To Secure FusionReactor And JSP Applications In Tomcat Using LDAP appeared first on FusionReactor Observability & APM.

]]>