Juraj Blahunka

A Java Swift enthusiast

© 2023. Juraj Blahunka All rights reserved.

Force automatic reload of "Expires: never" resources (css, js)

During website development, you have probably already experienced following situation:

  1. Make significant changes to website CSS
  2. Deploy changed CSS to webserver / app server
  3. Verify changed resource by navigating to website an pressing “Reload”
  4. Everything looks allright, you pack your bags and head home

And the story continues… You arrive home and you realize, that your CSS is not refreshed. What happened wrong? You start to investigate. Then you realize, that the resource was cached by your browser and doesn’t change on a simple page request, because you are using a long resource expiration.

Handling resource cache expiration

What if you just decrease duration of cache expiration? You will not use never, but browser clients will redownload your resources every day.

This change shuld be very straight forward. Depending on your technology stack, you just provide correct configuration. In nginx, one day resource expiration would look like this:

location ~* \.(css)$ {
	expires 1d;
}

As you can see, it is not very flexible. Either you must always conform to a common filename pattern, or you will always have to enumerate all your resources by hand. What if you want to see changed resources in that instant without too much hassle?

Append URL query parameter to your resource

By adding a changing query parameter to your resource’s URL you solve these 2 issues, which were present with previous solution:

  • Resources expire at fixed interval and browser is force to reload them even if they didn’t change
  • Cache expiry configuration changes between different technology stacks

Let’s put it to the test. Create a website and add a <link> to your CSS in the <head> section. If you look into this website sources, you will see following stylesheet declaration:

<link rel="stylesheet" href="/public/css/custom.css?201405190923">

Notice the 201405190923 parameter in the end. It’s the date and time of last build.

Every frontend technology handles resource output differently, but all have one thing in common:

Stylesheet resource is linked to the website by a URL. Guess what? You should have full control over this URL in all frontend stacks.

By defining a variable, which changes only from build to build, you have fine grained control over stylesheet resources expiration, which now expire as you please and you can distribute them with “Never” expiry policy.

Recover from GTID replication relay log error in MySQL 5.6 using GTID_PURGED

Recently, we had an error in our production system. Replication on MySQL Slave failed. It was not caused by a bug, but by an unexpected Slave server restart of the whole machine. After checking SHOW SLAVE STATUS\G we got scared, that Master’s binlog is also corrupt, which happened not so long ago - MySQL Bug #7022.

Fortunately, Master’s binlog was intact, so we moved back to Slave, to solve the problem (removed MySQL noise for brevity):

mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
...
Slave_IO_Running: Yes
Slave_SQL_Running: No
...
Last_Errno: 1594
Last_Error: Relay log read failure: Could not parse relay log event entry. The possible reasons are: the master's binary log is corrupted (you can check this by running 'mysqlbinlog' on the binary log), the slave's relay log is corrupted (you can check this by running 'mysqlbinlog' on the relay log), a network problem, or a bug in the master's or slave's MySQL code. If you want to check the master's binary log or slave's relay log, you will be able to know their names by issuing 'SHOW SLAVE
...
Executed_Gtid_Set: 3aabcfda-591d-11e3-81f1-0050569a4585:1-14351185
Auto_Position: 1
1 row in set (0.00 sec)

You can see from the output, that we are using GTID replication, which is available since MySQL 5.6. Transactions 1-14351185 were executed successfully, but the 14351186 got corrupt. We tried to skip it by committing an empty GTID transaction, but that did not help.

What to do next? At this point I wanted to start crying, because multiple sites and tutorials suggest to perform a clean mysqldump of Master, which will be copied to Slave. That is “the correct” way of solving replication problems. However, shutting down a site, just to perform a ~700GB database dump is not fun at all.

MySQL 5.6 replication variables

Browsing through the net reveals a small number of pages, which mention this secret GTID_PURGED variable.

I didn’t comprehend the meaning of this variable at first (straight from dev.mysql.com):

The set of all transactions that have been purged from the binary log.

But after some digging, it has definitely its place inside MySQL.

By changing the GTID_PURGED on Slave, we can inform the server about missing binary logs on Master, so Slave starts replication from the next available transaction identifier. This way, we don’t have to perform a full Master Slave backup. Just make sure, that binlogs, which you want to synchronize are still present on Master.

Work your magic GTID_PURGED!

1. Reset available replication information on Slave, so Slave forgets its own binlogs and Master’s relay logs.

mysql> RESET SLAVE;
mysql> RESET MASTER;

2. Issue a command to reconfigure replication by pointing Slave to Master (which was cleared in previous step):

mysql> CHANGE MASTER TO
MASTER_HOST = '...',
MASTER_PORT = ...,
MASTER_USER = '...',
MASTER_PASSWORD = '...',
MASTER_AUTO_POSITION = 1;

3. We are ready to instruct Slave with information about deleted binlogs on Master, so Slave will not replicate them and they will be skipped.

_The reason, why we want to skip some transactions, is because they were already replicated to Slave before._
mysql> SET global GTID_PURGED="3aabcfda-591d-11e3-81f1-0050569a4585:1-14351185";

4. We are done with preparations. All, that is left to be done is to start the replication:

mysql> START SLAVE;

5. And check if both Slave replication threads are doing their work without errors:

*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
...
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...
Seconds_Behind_Master: 157717
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
...
Retrieved_Gtid_Set: 3aabcfda-591d-11e3-81f1-0050569a4585:14351185-14805026
Executed_Gtid_Set: 3aabcfda-591d-11e3-81f1-0050569a4585:1-14351185
Auto_Position: 1
1 row in set (0.00 sec)

MySQL is a great database, which solves problems it is meant to solve. New replication functionality (GTID) however has it quirks when compared to the “old” replication by master log coordinates. Hopefully, this post will help others when solving similar problems with bringing replication back to life after Slave failure.

Inject JBoss 7 system properties into your Java EE application

How do you make your Java EE application configurable? Do you use Maven profiles? Properties file? Environment properties? If you have developed with JBoss 7 before, you have probably already heard about JBoss 7 System Properties.

They are usually specified in configuration file of mode specific directory, for example standalone, they are persistent (live through server restarts) and can be configured, most usually via jboss-cli.

One of the great things about Java EE application development is its flexibility. Why not use this flexibility to inject these properties into runtime?

In following lines you will see:

  • how to inject JBoss system properties into runtime
  • REST resource demonstration
  • that you don’t need to read it, just fork the project on GitHub

CDI annotations to the rescue

First, we need to define, how would our default access pattern look. Let’s leverage the @Inject annotation with a custom @Qualifier:

@Inject
@SystemProperty("example.foo")
String foo;

Now, let’s define the @SystemProperty annotation:

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
public @interface SystemProperty {

	/**
	 * Full name of the system property, for example "user.home"
	 */
	@Nonbinding String value();

}

Note, that we do not define default "" next to our value(), since the property name should be always defined. Therefore we automatically disallow usage of empty system property @SystemProperty().

And how will the System property get from JBoss to our little @SystemProperty annotated variable? Let’s define a provider, who uses the @Produces annotation and provides our application with concrete system properties:

public class SystemPropertyProvider {
^
	@Produces
	@SystemProperty("")
	String findProperty(InjectionPoint ip) {
		SystemProperty annotation = ip.getAnnotated()
			.getAnnotation(SystemProperty.class);

		String name = annotation.value();
		String found = System.getProperty(name);
		if (found == null) {
			throw new IllegalStateException("System property '" + name + "' is not defined!");
		}
		return found;
	}

}

Demonstration

After we have defined our deliver mechanism, we probably want to use our new @SystemProperty annotation. Let’s define an example REST resource:

@Path("example")
public class ExampleResource {

	@Inject
	@SystemProperty("example.foo")
	String foo;

	@Inject
	@SystemProperty("example.bar")
	String bar;

	@GET
	@Produces(MediaType.TEXT_PLAIN)
	public String printSomeSystemProperties() {
		return "foo=" + foo + ", bar=" + bar;
	}

}

Deploy to JBoss 7 and hit http://localhost:8080/inject-jboss-system-properties/example. But what happened? We are getting an exception:

java.lang.IllegalStateException: System property 'example.foo' is not defined!
	sk.blahunka.jbossinject.properties.SystemPropertyProvider.findProperty(SystemPropertyProvider.java:15)

We forgot about our properties, to define them, we will use the good old jboss-cli. On windows, fire up the jboss-cli.bat executable and type in:

connect

/system-property=example.foo:add(value="Special Foo Value")
/system-property=example.bar:add(value="Why is Foo so special?")

Then hit refresh in your browser and voila, our properties were injected:

foo=Special Foo Value, bar=Why is Foo so special?

You can fork the inject-jboss-system-properties project on GitHub.

Hello, world!

I did it! My first steps with new platform and legendary words every programmer is happy to see. Hello, world! And hello to you!

Welcome to my Blog, a place, where I will discuss my thoughts on software development. I hope, that I will achieve at least some of following goals:

  • Contribute to the Open Source community, so expect musings about personal projects (GitHub).
  • Remind myself about stuff I tend to forget, so expect mental notes about small pieces of technology.
  • Create content, which is easy to read, understand and process, so expect a lot of:
try {
	writeContent();
} catch (NoPointInPublishingException e) {
	tryAgain();
}

My name is Juraj Blahunka and I’m Java+.