I developed my TimerJobs as features in Sharepoint, with the full wsp file.
The job deploys well using stsadm with install and deploy.

I can also successfully run retract and delete the solution using stsadm.

However quite often once I re-run the installation or try to upgrade the solution, the
end result is that the original job is still running. The installation does not give any error
messages, but logging reveals that its still running the old code.

After banging my head on my desk for a while I sat down and thought about how Sharepoint
executes the jobs.

The Windows Service ‘Windows SharePoint Services Timer’ actually runs the jobs and manages them, which again is a fancy name for the following executable "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\BIN\OWSTIMER.EXE"

If I restart this service the latest and greatest assembly for the job will be executed.

I have found that the most elegant way of developing the jobs is to develop the core code as a separate strongly typed assembly.  The core code assembly is invoked by a a job harness. The job harness contains only the most vital code to create a SPJobDefinition, and nothing else, save for one or two line invocations of the CoreCode.

Once a new feature is added to the core code, or in some cases, perhaps a bug is fixed, simply un-install the CoreCode assembly from the GAC, install the new one and restart the OWSTIMER service.

That way I save the time doing the upgrade/install-update/retract-delete solutions.

Mind you, this is only for the development phase. Always develop the wsp file for installation and deployment in test and production.